Reconcile with gingerbread-release honeycomb-release
Change-Id: I8e71c24c079299c073c2b274e9f6aaf1ad960164
diff --git a/Android.mk b/Android.mk
index ff1b7e2..1c9dcc4 100644
--- a/Android.mk
+++ b/Android.mk
@@ -5,7 +5,11 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := com.android.phone.common com.android.vcard android-common
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ com.android.phone.common \
+ com.android.vcard \
+ android-common \
+ guava
LOCAL_PACKAGE_NAME := Contacts
LOCAL_CERTIFICATE := shared
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 52562e0..5969097 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -46,7 +46,7 @@
>
<!-- A virtual 12 key dialer -->
- <activity android:name="TwelveKeyDialer"
+ <activity android:name=".activities.DialpadActivity"
android:launchMode="singleTop"
>
<intent-filter>
@@ -57,7 +57,7 @@
</activity>
<!-- A list of recent calls -->
- <activity android:name="RecentCallsListActivity"
+ <activity android:name=".activities.CallLogActivity"
android:label="@string/recentCallsIconLabel"
>
<intent-filter>
@@ -119,7 +119,7 @@
</activity>
<!-- Tab container for all tabs -->
- <activity android:name="DialtactsActivity"
+ <activity android:name=".activities.DialtactsActivity"
android:label="@string/launcherDialer"
android:theme="@style/DialtactsTheme"
android:launchMode="singleTask"
@@ -185,16 +185,6 @@
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
-
- <intent-filter>
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:mimeType="vnd.android.cursor.dir/person" />
- <data android:mimeType="vnd.android.cursor.dir/contact" />
- <data android:mimeType="vnd.android.cursor.item/person" />
- <data android:mimeType="vnd.android.cursor.item/contact" />
- <data android:mimeType="vnd.android.cursor.item/raw_contact" />
- </intent-filter>
</activity>
<!-- The actual list of contacts -->
@@ -291,6 +281,7 @@
<data android:mimeType="vnd.android.cursor.dir/phone" />
<data android:mimeType="vnd.android.cursor.dir/postal-address_v2" />
<data android:mimeType="vnd.android.cursor.dir/postal-address" />
+ <data android:mimeType="vnd.android.cursor.dir/email_v2" />
</intent-filter>
<intent-filter>
@@ -335,7 +326,7 @@
<activity
android:name=".activities.ShowOrCreateActivity"
- android:theme="@style/FullyTranslucent">
+ android:theme="@android:style/Theme.Translucent.NoTitleBar">
<intent-filter>
<action android:name="com.android.contacts.action.SHOW_OR_CREATE_CONTACT" />
@@ -345,16 +336,36 @@
</intent-filter>
</activity>
+
+ <!-- List of groups -->
+ <activity android:name=".activities.GroupBrowserActivity"
+ android:label="@string/contactsGroupsLabel"
+ android:theme="@style/ContactBrowserTheme"
+ android:launchMode="singleTop"
+ android:clearTaskOnLaunch="true">
+ <!-- TODO: Remove this temporary intent action name when the fragmentization
+ work is done. -->
+ <intent-filter>
+ <action android:name="com.android.phone.action.GROUPS_LIST" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.TAB" />
+ </intent-filter>
+ </activity>
+
+ <!-- Views the details of a single group -->
+ <activity android:name=".activities.GroupDetailActivity"
+ android:label=""
+ android:theme="@style/GroupDetailTheme" />
+
<!-- Used to show QuickContact window over a translucent activity, which is a
temporary hack until we add better framework support. -->
<activity
- android:name=".quickcontact.QuickContactActivity"
- android:theme="@style/FullyTranslucent.QuickContact"
+ android:name=".quickcontact.QuickContactWindow"
+ android:theme="@style/Theme.QuickContact"
android:launchMode="singleTop"
android:excludeFromRecents="true"
android:taskAffinity="android.task.quickcontact"
- android:windowSoftInputMode="stateUnchanged"
- >
+ android:windowSoftInputMode="stateUnchanged">
<intent-filter>
<action android:name="com.android.contacts.action.QUICK_CONTACT" />
@@ -442,6 +453,11 @@
<intent-filter android:label="@string/viewContactDesription">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
+ <data android:mimeType="vnd.android.cursor.dir/person" />
+ <data android:mimeType="vnd.android.cursor.dir/contact" />
+ <data android:mimeType="vnd.android.cursor.item/person" />
+ <data android:mimeType="vnd.android.cursor.item/contact" />
+ <data android:mimeType="vnd.android.cursor.item/raw_contact" />
</intent-filter>
</activity>
@@ -550,7 +566,7 @@
<!-- vCard related -->
<activity android:name=".vcard.ImportVCardActivity"
- android:configChanges="orientation"
+ android:configChanges="orientation|screenSize|keyboardHidden"
android:theme="@style/BackgroundOnly">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
diff --git a/res/drawable-hdpi/divider_horizontal_light.png b/res/drawable-hdpi/divider_horizontal_light.png
new file mode 100644
index 0000000..20d7a01
--- /dev/null
+++ b/res/drawable-hdpi/divider_horizontal_light.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/panel_message.9.png b/res/drawable-hdpi/panel_message.9.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/panel_message.9.png
rename to res/drawable-hdpi/panel_message.9.png
Binary files differ
diff --git a/res/drawable-mdpi/divider_horizontal_light.png b/res/drawable-mdpi/divider_horizontal_light.png
new file mode 100644
index 0000000..20d7a01
--- /dev/null
+++ b/res/drawable-mdpi/divider_horizontal_light.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/panel_message.9.png b/res/drawable-mdpi/panel_message.9.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/panel_message.9.png
rename to res/drawable-mdpi/panel_message.9.png
Binary files differ
diff --git a/res/drawable/quickactions_arrow_left_holo_light.xml b/res/drawable/quickactions_arrow_left_holo_light.xml
new file mode 100644
index 0000000..c1e18bd
--- /dev/null
+++ b/res/drawable/quickactions_arrow_left_holo_light.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_first="true" android:drawable="@drawable/quickactions_arrowdown_left_holo_light" />
+ <item android:state_last="true" android:drawable="@drawable/quickactions_arrowup_left_holo_light" />
+ <!-- TODO: provide callout-less state -->
+ <item android:drawable="@drawable/quickactions_arrowup_left_holo_light" />
+</selector>
diff --git a/res/drawable/quickactions_arrow_middle_holo_light.xml b/res/drawable/quickactions_arrow_middle_holo_light.xml
new file mode 100644
index 0000000..f88b513
--- /dev/null
+++ b/res/drawable/quickactions_arrow_middle_holo_light.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_first="true" android:drawable="@drawable/quickactions_arrowdown_middle_holo_light" />
+ <item android:state_last="true" android:drawable="@drawable/quickactions_arrowup_middle_holo_light" />
+ <!-- TODO: provide callout-less state -->
+ <item android:drawable="@drawable/quickactions_arrowup_middle_holo_light" />
+</selector>
diff --git a/res/drawable/quickactions_arrow_right_holo_light.xml b/res/drawable/quickactions_arrow_right_holo_light.xml
new file mode 100644
index 0000000..3e309fe
--- /dev/null
+++ b/res/drawable/quickactions_arrow_right_holo_light.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_first="true" android:drawable="@drawable/quickactions_arrowdown_right_holo_light" />
+ <item android:state_last="true" android:drawable="@drawable/quickactions_arrowup_right_holo_light" />
+ <!-- TODO: provide callout-less state -->
+ <item android:drawable="@drawable/quickactions_arrowup_right_holo_light" />
+</selector>
diff --git a/res/layout-land/twelve_key_dialer.xml b/res/layout-land/dialpad_fragment.xml
similarity index 97%
rename from res/layout-land/twelve_key_dialer.xml
rename to res/layout-land/dialpad_fragment.xml
index 985d047..fe9fb28 100644
--- a/res/layout-land/twelve_key_dialer.xml
+++ b/res/layout-land/dialpad_fragment.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2006 The Android Open Source Project
+<!-- 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.
diff --git a/res/layout-long-land/twelve_key_dialer.xml b/res/layout-long-land/dialpad_fragment.xml
similarity index 97%
rename from res/layout-long-land/twelve_key_dialer.xml
rename to res/layout-long-land/dialpad_fragment.xml
index 1cf9690..f287741 100644
--- a/res/layout-long-land/twelve_key_dialer.xml
+++ b/res/layout-long-land/dialpad_fragment.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
+<!-- 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.
diff --git a/res/layout-long/twelve_key_dialer.xml b/res/layout-long/dialpad_fragment.xml
similarity index 88%
rename from res/layout-long/twelve_key_dialer.xml
rename to res/layout-long/dialpad_fragment.xml
index bd90df4..85250e2 100644
--- a/res/layout-long/twelve_key_dialer.xml
+++ b/res/layout-long/dialpad_fragment.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
+<!-- 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.
@@ -14,11 +14,14 @@
limitations under the License.
-->
+<!-- TODO (stopship) We don't want to specify a background color here. For now we just
+keep it because otherwise the dialer needs some imagination to use (white on white) -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/top"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
+ android:background="@android:color/black"
>
<!-- Text field above the keypad where the digits are displayed.
diff --git a/res/layout-xlarge-land/contact_detail_list_item.xml b/res/layout-xlarge-land/contact_detail_list_item.xml
index 529059a..9ad0e1b 100644
--- a/res/layout-xlarge-land/contact_detail_list_item.xml
+++ b/res/layout-xlarge-land/contact_detail_list_item.xml
@@ -23,42 +23,33 @@
android:layout_height="wrap_content"
android:orientation="vertical">
- <!-- Longer separating line (between kinds) -->
- <View
- android:id="@+id/kind_divider"
- android:layout_width="match_parent"
- android:layout_height="1px"
- android:background="@drawable/list_item_divider_holo" />
-
- <!-- Shorter separating line if there was no kind-separator -->
- <View
- android:id="@+id/in_kind_divider"
- android:layout_width="match_parent"
- android:layout_height="1px"
- android:layout_marginLeft="164dip"
- android:background="@drawable/list_item_divider_holo" />
-
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="vertical"
android:minHeight="@dimen/detail_min_line_item_height">
+
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center_vertical">
- <TextView
- android:id="@+id/kind"
- android:layout_width="164dip"
+
+ <FrameLayout
+ android:layout_width="@dimen/detail_item_type_width"
android:layout_height="@dimen/detail_min_line_item_height"
- android:paddingLeft="19dip"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorTertiary"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:gravity="center_vertical" />
+ android:paddingLeft="@dimen/detail_item_side_margin">
+
+ <TextView
+ android:id="@+id/kind"
+ style="@style/ContactDetailItemType" />
+
+ <TextView
+ android:id="@+id/type"
+ style="@style/ContactDetailItemType" />
+
+ </FrameLayout>
<LinearLayout
android:layout_width="wrap_content"
@@ -67,26 +58,21 @@
android:layout_weight="1"
android:paddingLeft="12dip"
android:orientation="vertical">
+
<TextView
android:id="@+id/data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium" />
+
<TextView
android:id="@+id/footer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:visibility="gone" />
+
</LinearLayout>
- <TextView
- android:id="@+id/type"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/detail_min_line_item_height"
- android:maxWidth="150dip"
- android:gravity="right|center_vertical"
- android:textColor="@color/detail_item_type_color"
- android:textAppearance="?android:attr/textAppearanceSmall" />
<ImageView
android:id="@+id/presence_icon"
@@ -96,14 +82,6 @@
android:gravity="center"
android:scaleType="centerInside" />
- <ImageView
- android:id="@+id/action_icon"
- android:layout_width="32dip"
- android:layout_height="@dimen/detail_min_line_item_height"
- android:layout_marginLeft="16dip"
- android:layout_gravity="center_vertical"
- android:scaleType="centerInside" />
-
<View
android:id="@+id/divider"
android:layout_width="1px"
@@ -114,21 +92,28 @@
android:layout_marginRight="14dip"
android:background="?android:attr/dividerVertical" />
- <ImageView
- android:id="@+id/secondary_action_button"
- android:layout_width="32dip"
+ <FrameLayout
+ android:id="@+id/secondary_action_button_container"
+ android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_centerVertical="true"
- android:gravity="center"
- android:scaleType="center"
- android:background="?android:attr/selectableItemBackground" />
+ android:layout_marginTop="10dip"
+ android:paddingLeft="@dimen/detail_item_icon_margin"
+ android:paddingRight="@dimen/detail_item_icon_margin"
+ android:duplicateParentState="false"
+ android:background="?android:attr/selectableItemBackground">
+
+ <ImageView
+ android:id="@+id/secondary_action_button"
+ android:layout_width="32dip"
+ android:layout_height="match_parent"
+ android:layout_centerVertical="true"
+ android:gravity="center"
+ android:scaleType="center"
+ android:duplicateParentState="false" />
+
+ </FrameLayout>
</LinearLayout>
+
</LinearLayout>
- <!-- Longer separating line (only for the last row) -->
- <View
- android:id="@+id/line_below_last"
- android:layout_width="match_parent"
- android:layout_height="1px"
- android:background="@drawable/list_item_divider_holo" />
</LinearLayout>
diff --git a/res/layout-xlarge/account_selector_list_item.xml b/res/layout-xlarge/account_selector_list_item.xml
new file mode 100644
index 0000000..38acfc5
--- /dev/null
+++ b/res/layout-xlarge/account_selector_list_item.xml
@@ -0,0 +1,45 @@
+<?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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+>
+ <ImageView android:id="@android:id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="6dip"
+ android:layout_centerVertical="true"
+ />
+
+ <TextView android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="6dip"
+ android:layout_marginTop="6dip"
+ android:layout_toRightOf="@android:id/icon"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ />
+
+ <TextView android:id="@android:id/text2"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/text1"
+ android:layout_alignLeft="@android:id/text1"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ />
+</RelativeLayout>
diff --git a/res/layout-xlarge/aggregation_suggestions_item.xml b/res/layout-xlarge/aggregation_suggestions_item.xml
index f12c608..5ea8347 100644
--- a/res/layout-xlarge/aggregation_suggestions_item.xml
+++ b/res/layout-xlarge/aggregation_suggestions_item.xml
@@ -24,6 +24,8 @@
android:orientation="horizontal"
android:paddingLeft="5dip"
android:paddingRight="15dip"
+ android:background="?android:attr/selectableItemBackground"
+ android:focusable="true"
>
<ImageView
android:id="@+id/aggregation_suggestion_photo"
diff --git a/res/layout-xlarge/contact_detail_fragment.xml b/res/layout-xlarge/contact_detail_fragment.xml
index 60d3cd5..4d6a900 100644
--- a/res/layout-xlarge/contact_detail_fragment.xml
+++ b/res/layout-xlarge/contact_detail_fragment.xml
@@ -23,25 +23,6 @@
android:layout_height="match_parent"
android:background="@drawable/panel_content">
- <!-- Header View (including social status) -->
- <com.android.contacts.widget.InterpolatingLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- >
- <com.android.contacts.detail.ContactDetailHeaderView
- android:id="@+id/contact_header_widget"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="28dip"
- ex:layout_wideParentWidth="800dip"
- ex:layout_wideMarginLeft="80dip"
- ex:layout_wideMarginRight="48dip"
- ex:layout_narrowParentWidth="500dip"
- ex:layout_narrowMarginLeft="15dip"
- ex:layout_narrowMarginRight="16dip"
- />
- </com.android.contacts.widget.InterpolatingLayout>
-
<!-- Placeholder for empty list -->
<com.android.contacts.widget.InterpolatingLayout
android:id="@android:id/empty"
@@ -78,7 +59,7 @@
ex:layout_narrowMarginLeft="32dip"
ex:layout_narrowPaddingRight="16dip"
android:cacheColorHint="#00000000"
- android:divider="@android:color/transparent"
+ android:divider="@null"
/>
</com.android.contacts.widget.InterpolatingLayout>
diff --git a/res/layout-xlarge/edit_spinner.xml b/res/layout-xlarge/edit_spinner.xml
new file mode 100644
index 0000000..f1909fe
--- /dev/null
+++ b/res/layout-xlarge/edit_spinner.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<!-- Spinner for a field in the contact editor. -->
+
+<Spinner
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/spinner"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/editor_field_left_padding"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:paddingLeft="5dip"
+ android:paddingTop="5dip"/>
\ No newline at end of file
diff --git a/res/layout-xlarge/event_field_editor_view.xml b/res/layout-xlarge/event_field_editor_view.xml
new file mode 100644
index 0000000..c9eef08
--- /dev/null
+++ b/res/layout-xlarge/event_field_editor_view.xml
@@ -0,0 +1,56 @@
+<?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.
+-->
+
+<!-- Editor for a single event entry in the contact editor -->
+
+<com.android.contacts.editor.EventFieldEditorView
+ 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:orientation="vertical">
+
+ <include
+ android:id="@+id/title"
+ layout="@layout/edit_field_title" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ android:gravity="bottom"
+ android:focusable="true"
+ android:clickable="true">
+
+ <include
+ android:id="@+id/date_view"
+ layout="@layout/edit_date_picker" />
+
+ <include
+ android:id="@+id/spinner"
+ layout="@layout/edit_spinner"
+ android:paddingTop="15dip"
+ android:visibility="gone" />
+
+ <include
+ android:id="@+id/delete_button_container"
+ layout="@layout/edit_delete_button"
+ android:visibility="gone" />
+
+ </LinearLayout>
+
+</com.android.contacts.editor.EventFieldEditorView>
diff --git a/res/layout-xlarge/item_kind_section.xml b/res/layout-xlarge/item_kind_section.xml
index 57de26d..f0ae1dc 100644
--- a/res/layout-xlarge/item_kind_section.xml
+++ b/res/layout-xlarge/item_kind_section.xml
@@ -20,41 +20,22 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal">
+ android:paddingBottom="@dimen/editor_field_bottom_padding"
+ android:orientation="vertical">
- <TextView
- android:id="@+id/kind_title"
- android:layout_width="150dip"
- android:layout_height="@dimen/editor_min_line_item_height"
- android:gravity="center_vertical"
- android:textColor="#7F7F7F"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:singleLine="true"
- android:ellipsize="marquee" />
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/divider_horizontal_light" />
<LinearLayout
android:id="@+id/kind_editors"
- android:layout_width="0dip"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_gravity="bottom"
android:orientation="vertical" />
- <FrameLayout
- android:id="@+id/kind_plus_container"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/editor_min_line_item_height">
- <ImageButton
- android:id="@+id/kind_plus"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:paddingLeft="@dimen/editor_round_button_padding_left"
- android:paddingRight="@dimen/editor_round_button_padding_right"
- android:paddingTop="@dimen/editor_round_button_padding_top"
- android:paddingBottom="@dimen/editor_round_button_padding_bottom"
- android:background="?android:attr/selectableItemBackground"
- android:src="@drawable/ic_menu_add_field_holo_light"
- android:contentDescription="@string/description_plus_button" />
- </FrameLayout>
+ <include
+ android:id="@+id/add_field_footer"
+ layout="@layout/edit_add_field" />
+
</com.android.contacts.editor.KindSectionView>
diff --git a/res/layout-xlarge/list_section.xml b/res/layout-xlarge/list_section.xml
deleted file mode 100644
index c684a0f..0000000
--- a/res/layout-xlarge/list_section.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<!-- Layout used for list section separators. -->
-<RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="37dip"
- android:background="@drawable/section_header_holo"
- >
- <TextView
- android:id="@+id/header_text"
- android:layout_width="56dip"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_alignParentLeft="true"
- android:textStyle="bold"
- android:textColor="@color/section_header_text_color"
- android:textSize="14sp"
- android:gravity="center"
- />
-</RelativeLayout>
diff --git a/res/layout-xlarge/phonetic_name_editor_view.xml b/res/layout-xlarge/phonetic_name_editor_view.xml
new file mode 100644
index 0000000..c3fa6a3
--- /dev/null
+++ b/res/layout-xlarge/phonetic_name_editor_view.xml
@@ -0,0 +1,59 @@
+<?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.
+-->
+
+<com.android.contacts.editor.PhoneticNameEditorView
+ 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:orientation="vertical"
+ android:paddingRight="?android:attr/scrollbarSize"
+ android:layout_marginLeft="52dip"
+ android:layout_marginRight="48dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="4dip">
+
+ <include
+ android:id="@+id/spinner"
+ layout="@layout/edit_spinner"
+ android:visibility="gone" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:focusable="true"
+ android:clickable="true">
+
+ <include
+ android:id="@+id/editors"
+ layout="@layout/edit_field_list" />
+
+ <include
+ android:id="@+id/expansion_view_container"
+ layout="@layout/edit_expansion_view"
+ android:visibility="gone" />
+
+ <include
+ android:id="@+id/delete_button_container"
+ layout="@layout/edit_delete_button"
+ android:visibility="gone" />
+
+ </LinearLayout>
+
+</com.android.contacts.editor.PhoneticNameEditorView>
diff --git a/res/layout-xlarge/raw_contact_editor_header.xml b/res/layout-xlarge/raw_contact_editor_header.xml
index a973464..498998d 100644
--- a/res/layout-xlarge/raw_contact_editor_header.xml
+++ b/res/layout-xlarge/raw_contact_editor_header.xml
@@ -16,52 +16,53 @@
<!-- Account info header -->
-<RelativeLayout
+<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="64dip"
- android:layout_width="match_parent"
- android:background="?android:attr/selectableItemBackground">
+ android:layout_width="match_parent">
- <ImageView
- android:id="@+id/header_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="7dip"
- android:layout_marginRight="7dip"
- android:layout_centerVertical="true"
- android:layout_alignParentRight="true"
- android:layout_below="@id/header_color_bar" />
-
- <TextView
- android:id="@+id/header_account_type"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toLeftOf="@+id/header_icon"
- android:layout_alignTop="@id/header_icon"
- android:layout_marginTop="-4dip"
-
- android:textSize="24sp"
- android:textColor="?android:attr/textColorPrimary"
- android:singleLine="true" />
-
- <TextView
- android:id="@+id/header_account_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toLeftOf="@+id/header_icon"
- android:layout_alignBottom="@+id/header_icon"
- android:layout_marginBottom="2dip"
-
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorPrimary"
- android:singleLine="true" />
-
- <View
- android:id="@+id/divider"
+ <RelativeLayout
+ android:id="@+id/account"
android:layout_width="match_parent"
- android:layout_height="1px"
- android:layout_alignParentBottom="true"
- android:background="?android:attr/listDivider"
- android:visibility="gone" />
+ android:layout_height="match_parent"
+ android:background="?android:attr/selectableItemBackground">
-</RelativeLayout>
+ <ImageView
+ android:id="@+id/account_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/header_color_bar" />
+
+ <TextView
+ android:id="@+id/account_type"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toLeftOf="@+id/account_icon"
+ android:layout_alignTop="@id/account_icon"
+ android:layout_marginTop="-4dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorPrimary"
+ android:singleLine="true" />
+
+ <TextView
+ android:id="@+id/account_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toLeftOf="@+id/account_icon"
+ android:layout_alignBottom="@+id/account_icon"
+ android:layout_marginBottom="2dip"
+
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorPrimary"
+ android:singleLine="true" />
+
+ <include
+ android:id="@+id/divider"
+ android:layout_alignParentBottom="true"
+ layout="@layout/edit_divider" />
+ </RelativeLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/res/layout-xlarge/raw_contact_editor_view.xml b/res/layout-xlarge/raw_contact_editor_view.xml
index 044a5ea..0e3d227 100644
--- a/res/layout-xlarge/raw_contact_editor_view.xml
+++ b/res/layout-xlarge/raw_contact_editor_view.xml
@@ -21,9 +21,14 @@
android:layout_height="wrap_content"
android:orientation="vertical">
- <include
- layout="@layout/raw_contact_editor_header"
- android:id="@+id/header" />
+ <FrameLayout
+ android:id="@+id/anchor_for_account_switcher"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <include
+ layout="@layout/raw_contact_editor_header"
+ android:id="@+id/header" />
+ </FrameLayout>
<LinearLayout
android:id="@+id/body"
@@ -67,23 +72,27 @@
android:layout_height="1px"
android:background="@color/contact_detail_header_divider_color" />
- <com.android.contacts.editor.TextFieldsEditorView
+ <include
android:id="@+id/edit_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingRight="?android:attr/scrollbarSize"
- android:layout_marginLeft="52dip"
- android:layout_marginRight="48dip"
- android:layout_marginTop="6dip"
- android:layout_marginBottom="4dip" />
+ layout="@layout/structured_name_editor_view" />
- <ViewStub
- android:id="@+id/aggregation_suggestion_stub"
- android:inflatedId="@+id/aggregation_suggestion"
- android:layout="@layout/aggregation_suggestions"
+ <include
+ android:id="@+id/edit_phonetic_name"
+ layout="@layout/phonetic_name_editor_view" />
+
+ <FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:visibility="visible" />
+ android:layout_marginLeft="52dip"
+ android:layout_marginRight="48dip">
+ <ViewStub
+ android:id="@+id/aggregation_suggestion_stub"
+ android:inflatedId="@+id/aggregation_suggestion"
+ android:layout="@layout/aggregation_suggestions"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="visible" />
+ </FrameLayout>
</LinearLayout>
</com.android.contacts.widget.InterpolatingLayout>
diff --git a/res/layout-xlarge/structured_name_editor_view.xml b/res/layout-xlarge/structured_name_editor_view.xml
new file mode 100644
index 0000000..37b5536
--- /dev/null
+++ b/res/layout-xlarge/structured_name_editor_view.xml
@@ -0,0 +1,58 @@
+<?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.
+-->
+
+<com.android.contacts.editor.StructuredNameEditorView
+ 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:orientation="vertical"
+ android:paddingRight="?android:attr/scrollbarSize"
+ android:layout_marginLeft="52dip"
+ android:layout_marginRight="48dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="4dip">
+
+ <include
+ android:id="@+id/spinner"
+ layout="@layout/edit_spinner"
+ android:visibility="gone" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ android:focusable="true"
+ android:clickable="true">
+
+ <include
+ android:id="@+id/editors"
+ layout="@layout/edit_field_list" />
+
+ <include
+ android:id="@+id/expansion_view_container"
+ layout="@layout/edit_expansion_view"
+ android:visibility="gone" />
+
+ <include
+ android:id="@+id/delete_button_container"
+ layout="@layout/edit_delete_button"
+ android:visibility="gone" />
+
+ </LinearLayout>
+
+</com.android.contacts.editor.StructuredNameEditorView>
diff --git a/res/layout-xlarge/text_fields_editor_view.xml b/res/layout-xlarge/text_fields_editor_view.xml
new file mode 100644
index 0000000..8be354b
--- /dev/null
+++ b/res/layout-xlarge/text_fields_editor_view.xml
@@ -0,0 +1,59 @@
+<?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.
+-->
+
+<com.android.contacts.editor.TextFieldsEditorView
+ 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:orientation="vertical">
+
+ <include
+ android:id="@+id/title"
+ layout="@layout/edit_field_title" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ android:gravity="top"
+ android:focusable="true"
+ android:clickable="true">
+
+ <include
+ android:id="@+id/editors"
+ layout="@layout/edit_field_list" />
+
+ <include
+ android:id="@+id/spinner"
+ layout="@layout/edit_spinner"
+ android:paddingTop="15dip"
+ android:visibility="gone" />
+
+ <include
+ android:id="@+id/expansion_view_container"
+ layout="@layout/edit_expansion_view"
+ android:visibility="gone" />
+
+ <include
+ android:id="@+id/delete_button_container"
+ layout="@layout/edit_delete_button"
+ android:visibility="gone" />
+
+ </LinearLayout>
+
+</com.android.contacts.editor.TextFieldsEditorView>
diff --git a/res/layout/account_selector_list_item.xml b/res/layout/account_selector_list_item.xml
index 38acfc5..6fe2a50 100644
--- a/res/layout/account_selector_list_item.xml
+++ b/res/layout/account_selector_list_item.xml
@@ -17,29 +17,23 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
->
- <ImageView android:id="@android:id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="6dip"
- android:layout_centerVertical="true"
- />
+ android:paddingLeft="@dimen/account_selector_horizontal_margin"
+ android:paddingRight="@dimen/account_selector_horizontal_margin"
+ android:minHeight="@dimen/account_selector_min_item_height" >
<TextView android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="6dip"
- android:layout_marginTop="6dip"
- android:layout_toRightOf="@android:id/icon"
- android:textAppearance="?android:attr/textAppearanceLarge"
+ android:layout_alignParentLeft="true"
+ android:layout_toLeftOf="@android:id/icon"
+ android:layout_centerVertical="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
/>
- <TextView android:id="@android:id/text2"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@android:id/text1"
- android:layout_alignLeft="@android:id/text1"
- android:textAppearance="?android:attr/textAppearanceSmall"
+ <ImageView android:id="@android:id/icon"
+ android:layout_width="@dimen/account_selector_icon_size"
+ android:layout_height="@dimen/account_selector_icon_size"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
/>
</RelativeLayout>
diff --git a/res/layout/aggregation_suggestions_item.xml b/res/layout/aggregation_suggestions_item.xml
index f2477cb..9ed1bf3 100644
--- a/res/layout/aggregation_suggestions_item.xml
+++ b/res/layout/aggregation_suggestions_item.xml
@@ -24,6 +24,8 @@
android:orientation="horizontal"
android:paddingLeft="5dip"
android:paddingRight="15dip"
+ android:background="?android:attr/selectableItemBackground"
+ android:focusable="true"
>
<ImageView
diff --git a/res/layout/recent_calls.xml b/res/layout/call_log_activity.xml
similarity index 63%
copy from res/layout/recent_calls.xml
copy to res/layout/call_log_activity.xml
index f054b70..b391795 100644
--- a/res/layout/recent_calls.xml
+++ b/res/layout/call_log_activity.xml
@@ -18,17 +18,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
>
- <ListView android:id="@android:id/list"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:scrollbarStyle="outsideOverlay"
- />
-
- <TextView android:id="@android:id/empty"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:text="@string/recentCalls_empty"
- android:gravity="center"
- android:textAppearance="?android:attr/textAppearanceLarge"
- />
+ <fragment class="com.android.contacts.calllog.CallLogFragment"
+ android:id="@+id/call_log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
</FrameLayout>
diff --git a/res/layout/recent_calls.xml b/res/layout/call_log_fragment.xml
similarity index 91%
rename from res/layout/recent_calls.xml
rename to res/layout/call_log_fragment.xml
index f054b70..2a27fcd 100644
--- a/res/layout/recent_calls.xml
+++ b/res/layout/call_log_fragment.xml
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
+<!-- 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.
@@ -19,11 +19,11 @@
android:layout_height="match_parent"
>
<ListView android:id="@android:id/list"
- android:layout_width="match_parent"
+ android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarStyle="outsideOverlay"
/>
-
+
<TextView android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/res/layout/recent_calls_list_child_item.xml b/res/layout/call_log_list_child_item.xml
similarity index 95%
rename from res/layout/recent_calls_list_child_item.xml
rename to res/layout/call_log_list_child_item.xml
index 527e259..bb48fcf 100644
--- a/res/layout/recent_calls_list_child_item.xml
+++ b/res/layout/call_log_list_child_item.xml
@@ -33,6 +33,6 @@
android:background="@drawable/call_background_secondary"
/>
- <include layout="@layout/recent_calls_list_item_layout"/>
+ <include layout="@layout/call_log_list_item_layout"/>
</RelativeLayout>
diff --git a/res/layout/recent_calls_list_group_item.xml b/res/layout/call_log_list_group_item.xml
similarity index 100%
rename from res/layout/recent_calls_list_group_item.xml
rename to res/layout/call_log_list_group_item.xml
diff --git a/res/layout/recent_calls_list_item.xml b/res/layout/call_log_list_item.xml
similarity index 95%
rename from res/layout/recent_calls_list_item.xml
rename to res/layout/call_log_list_item.xml
index 2c519d6..4ea0563 100644
--- a/res/layout/recent_calls_list_item.xml
+++ b/res/layout/call_log_list_item.xml
@@ -32,6 +32,6 @@
android:background="@drawable/call_background"
/>
- <include layout="@layout/recent_calls_list_item_layout"/>
+ <include layout="@layout/call_log_list_item_layout"/>
</RelativeLayout>
diff --git a/res/layout/recent_calls_list_item_layout.xml b/res/layout/call_log_list_item_layout.xml
similarity index 100%
rename from res/layout/recent_calls_list_item_layout.xml
rename to res/layout/call_log_list_item_layout.xml
diff --git a/res/layout/contact_browser.xml b/res/layout/contact_browser.xml
index 0b4bb63..8affd46 100644
--- a/res/layout/contact_browser.xml
+++ b/res/layout/contact_browser.xml
@@ -18,4 +18,25 @@
android:id="@+id/list_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
+ <FrameLayout
+ android:id="@+id/main_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <fragment
+ android:id="@+id/list_fragment"
+ class="com.android.contacts.list.DefaultContactBrowseListFragment"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ />
+ </FrameLayout>
+ <FrameLayout
+ android:id="@+id/contacts_unavailable_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone">
+ <FrameLayout
+ android:id="@+id/contacts_unavailable_container"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent" />
+ </FrameLayout>
</FrameLayout>
diff --git a/res/layout/contact_detail_fragment.xml b/res/layout/contact_detail_fragment.xml
index 90a075a..70a9a28 100644
--- a/res/layout/contact_detail_fragment.xml
+++ b/res/layout/contact_detail_fragment.xml
@@ -20,16 +20,12 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <com.android.contacts.detail.ContactDetailHeaderView
- android:id="@+id/contact_header_widget"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
-
<ListView android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"
- android:background="@drawable/title_bar_shadow"
+ android:background="@color/background_primary"
+ android:divider="@null"
/>
<ScrollView android:id="@android:id/empty"
diff --git a/res/layout/contact_detail_header_view.xml b/res/layout/contact_detail_header_view.xml
index 3248920..328a5ff 100644
--- a/res/layout/contact_detail_header_view.xml
+++ b/res/layout/contact_detail_header_view.xml
@@ -14,46 +14,53 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/banner"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal"
- android:background="@drawable/title_bar_medium"
- android:paddingRight="5dip">
+ android:layout_height="150dip">
<ImageView android:id="@+id/photo"
- android:layout_gravity="center_vertical"
- android:layout_marginLeft="-1dip"
- android:layout_marginTop="4dip"
- android:layout_marginBottom="4dip"
- android:layout_marginRight="8dip"
- android:layout_width="64dip"
- android:layout_height="64dip"
- />
+ android:scaleType="centerCrop"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ />
+
+ <!-- Transparent view to overlay on the contact's photo
+ (to allow white text to appear over a white photo). -->
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:background="#000000"
+ android:alpha=".25"
+ />
<LinearLayout
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:orientation="vertical"
- android:layout_gravity="center_vertical" >
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentLeft="true"
+ android:layout_marginLeft="10dip"
+ android:orientation="vertical" >
<TextView android:id="@+id/name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_height="0dip"
+ android:layout_weight="1"
android:singleLine="true"
android:ellipsize="end"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textStyle="bold"
- android:shadowColor="#BB000000"
- android:shadowRadius="2.75"
+ android:gravity="bottom"
+ android:textSize="@dimen/detail_header_name_text_size"
+ android:textColor="@color/detail_header_view_text_color"
/>
<TextView android:id="@+id/phonetic_name"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/detail_header_view_text_color"
android:singleLine="true"
android:ellipsize="end"
android:layout_marginTop="-2dip"
@@ -61,9 +68,10 @@
/>
<TextView android:id="@+id/organization"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/detail_header_view_text_color"
android:singleLine="true"
android:ellipsize="end"
android:layout_marginTop="-2dip"
@@ -71,7 +79,7 @@
/>
<TextView android:id="@+id/attribution"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
@@ -82,9 +90,10 @@
/>
<TextView android:id="@+id/status"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="@color/detail_header_view_text_color"
android:singleLine="true"
android:ellipsize="end"
android:layout_marginTop="-2dip"
@@ -92,9 +101,8 @@
/>
<TextView android:id="@+id/status_date"
- android:layout_width="match_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="12sp"
android:layout_marginTop="-2dip"
@@ -106,9 +114,13 @@
android:id="@+id/star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginTop="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentRight="true"
android:layout_gravity="center_vertical"
android:contentDescription="@string/description_star"
android:visibility="invisible"
style="?android:attr/starStyle"
/>
-</LinearLayout>
+</RelativeLayout>
\ No newline at end of file
diff --git a/res/layout/contact_detail_header_view_list_item.xml b/res/layout/contact_detail_header_view_list_item.xml
new file mode 100644
index 0000000..cf149df
--- /dev/null
+++ b/res/layout/contact_detail_header_view_list_item.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+<com.android.contacts.detail.ContactDetailHeaderView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/contact_header_widget"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
\ No newline at end of file
diff --git a/res/layout/contact_detail_list_item.xml b/res/layout/contact_detail_list_item.xml
index 13b07bb..2e4a3e5 100644
--- a/res/layout/contact_detail_list_item.xml
+++ b/res/layout/contact_detail_list_item.xml
@@ -21,114 +21,71 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:paddingLeft="@dimen/detail_item_side_margin"
+ android:orientation="horizontal"
+ android:gravity="center_vertical">
- <!-- Seperator that shows the kind -->
<LinearLayout
- android:id="@+id/kind_divider"
- android:layout_width="match_parent"
+ android:layout_width="0dip"
android:layout_height="wrap_content"
- android:orientation="vertical">
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="1px"
- android:background="@drawable/list_item_divider_holo" />
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:gravity="center_vertical">
+
<TextView
android:id="@+id/kind"
- android:gravity="center_vertical"
- android:layout_width="match_parent"
- android:layout_height="31dip"
- android:paddingLeft="16dip"
+ style="@style/ContactDetailItemType" />
+
+ <TextView
+ android:id="@+id/type"
+ style="@style/ContactDetailItemType" />
+
+ <TextView
+ android:id="@+id/data"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingBottom="5dip"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <TextView
+ android:id="@+id/footer"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorTertiary" />
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="1px"
- android:background="@drawable/list_item_divider_holo" />
+ android:visibility="gone" />
</LinearLayout>
- <!-- Shorter seperating line if there was no kind-seperator -->
<ImageView
- android:id="@+id/in_kind_divider"
- android:layout_marginLeft="31dip"
- android:layout_width="match_parent"
- android:layout_height="1px"
- android:background="@drawable/list_item_divider_holo" />
-
- <LinearLayout
- android:layout_width="match_parent"
+ android:id="@+id/presence_icon"
+ android:layout_width="32dip"
android:layout_height="wrap_content"
- android:minHeight="@dimen/detail_min_line_item_height"
- android:orientation="horizontal"
- android:paddingLeft="31dip"
- android:gravity="center_vertical">
- <LinearLayout
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_marginLeft="5dip"
- android:orientation="vertical"
- android:paddingTop="5dip"
- android:paddingBottom="7dip"
- android:gravity="center_vertical">
+ android:layout_marginLeft="5dip"
+ android:gravity="center"
+ android:scaleType="centerInside" />
- <TextView
- android:id="@+id/data"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:textAppearance="?android:attr/textAppearanceMedium" />
+ <View
+ android:id="@+id/divider"
+ android:layout_width="1px"
+ android:layout_height="match_parent"
+ android:layout_marginTop="15dip"
+ android:layout_marginBottom="10dip"
+ android:background="?android:attr/dividerVertical" />
- <TextView
- android:id="@+id/type"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/detail_item_type_color" />
-
- <TextView
- android:id="@+id/footer"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:visibility="gone" />
-
- </LinearLayout>
-
- <ImageView
- android:id="@+id/presence_icon"
- android:layout_width="32dip"
- android:layout_height="wrap_content"
- android:layout_marginLeft="5dip"
- android:gravity="center"
- android:scaleType="centerInside" />
-
- <ImageView
- android:id="@+id/action_icon"
- android:layout_width="32dip"
- android:layout_height="32dip"
- android:layout_marginLeft="16dip"
- android:gravity="center"
- android:scaleType="centerInside" />
-
- <View
- android:id="@+id/divider"
- android:layout_width="1px"
- android:layout_height="match_parent"
- android:layout_marginTop="5dip"
- android:layout_marginBottom="5dip"
- android:layout_marginLeft="14dip"
- android:layout_marginRight="14dip"
- android:background="?android:attr/dividerVertical" />
-
+ <FrameLayout
+ android:id="@+id/secondary_action_button_container"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginTop="5dip"
+ android:paddingLeft="@dimen/detail_item_icon_margin"
+ android:paddingRight="@dimen/detail_item_icon_margin"
+ android:duplicateParentState="false"
+ android:background="?android:attr/selectableItemBackground">
<ImageView
android:id="@+id/secondary_action_button"
android:layout_width="32dip"
android:layout_height="match_parent"
- android:layout_centerVertical="true"
- android:gravity="center"
- android:scaleType="center"
- android:background="?android:attr/selectableItemBackground" />
- </LinearLayout>
+ android:duplicateParentState="false" />
+ </FrameLayout>
</LinearLayout>
diff --git a/res/layout/contact_detail_separator_list_item.xml b/res/layout/contact_detail_separator_list_item.xml
new file mode 100644
index 0000000..87f0597
--- /dev/null
+++ b/res/layout/contact_detail_separator_list_item.xml
@@ -0,0 +1,22 @@
+<?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:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:background="@drawable/divider_horizontal_light"
+ />
\ No newline at end of file
diff --git a/res/layout/contact_editor_activity.xml b/res/layout/contact_editor_activity.xml
index 630e82c..8c13629 100644
--- a/res/layout/contact_editor_activity.xml
+++ b/res/layout/contact_editor_activity.xml
@@ -22,21 +22,4 @@
android:id="@+id/contact_editor_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="50dip"
- android:orientation="horizontal"
- android:gravity="center_horizontal">
-
- <Button
- android:id="@+id/done"
- android:layout_width="150dip"
- android:layout_height="match_parent"
- android:text="@string/menu_done" />
- <Button
- android:id="@+id/revert"
- android:layout_width="150dip"
- android:layout_height="match_parent"
- android:text="@string/menu_doNotSave" />
- </LinearLayout>
</FrameLayout>
diff --git a/res/layout/contact_editor_fragment.xml b/res/layout/contact_editor_fragment.xml
index 602f7f9..f3989e1 100644
--- a/res/layout/contact_editor_fragment.xml
+++ b/res/layout/contact_editor_fragment.xml
@@ -17,6 +17,7 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:background="@color/background_primary"
>
<ScrollView
diff --git a/res/layout/dialer_activity.xml b/res/layout/dialer_activity.xml
deleted file mode 100644
index 14a6b39..0000000
--- a/res/layout/dialer_activity.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2006 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/tabhost"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <TabWidget android:id="@android:id/tabs"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- />
-
- <FrameLayout android:id="@android:id/tabcontent"
- android:layout_width="match_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
- />
- </LinearLayout>
-</TabHost>
-
diff --git a/res/layout/dialpad_activity.xml b/res/layout/dialpad_activity.xml
new file mode 100644
index 0000000..93e9523
--- /dev/null
+++ b/res/layout/dialpad_activity.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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+>
+ <fragment class="com.android.contacts.dialpad.DialpadFragment"
+ android:id="@+id/dialpad_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+</FrameLayout>
diff --git a/res/layout/twelve_key_dialer.xml b/res/layout/dialpad_fragment.xml
similarity index 89%
rename from res/layout/twelve_key_dialer.xml
rename to res/layout/dialpad_fragment.xml
index d4c9d8f..c516bd8 100644
--- a/res/layout/twelve_key_dialer.xml
+++ b/res/layout/dialpad_fragment.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2006 The Android Open Source Project
+<!-- 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.
@@ -14,11 +14,14 @@
limitations under the License.
-->
+<!-- TODO (stopship) We don't want to specify a background color here. For now we just
+keep it because otherwise the dialer needs some imagination to use (white on white) -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/top"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
+ android:background="@android:color/black"
>
<!-- Text field above the keypad where the digits are displayed.
diff --git a/res/layout/dialtacts_activity.xml b/res/layout/dialtacts_activity.xml
new file mode 100644
index 0000000..63ca3bd
--- /dev/null
+++ b/res/layout/dialtacts_activity.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <!-- Dialer --> -->
+ <fragment
+ class="com.android.contacts.dialpad.DialpadFragment"
+ android:id="@+id/dialpad_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <!-- Call Log -->
+ <fragment
+ class="com.android.contacts.calllog.CallLogFragment"
+ android:id="@+id/call_log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <!-- Contacts -->
+ <fragment
+ android:id="@+id/contacts_fragment"
+ class="com.android.contacts.list.DefaultContactBrowseListFragment"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent" />
+
+ <!-- Favorites -->
+ <fragment
+ android:id="@+id/favorites_fragment"
+ class="com.android.contacts.list.DefaultContactBrowseListFragment"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent" />
+</FrameLayout>
\ No newline at end of file
diff --git a/res/layout/edit_add_field.xml b/res/layout/edit_add_field.xml
new file mode 100644
index 0000000..1c8c740
--- /dev/null
+++ b/res/layout/edit_add_field.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.
+-->
+<!-- Layout of "add field" row in contact editor -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="13dip"
+ android:background="?android:attr/selectableItemBackground">
+ <TextView
+ android:id="@+id/add_text"
+ android:layout_gravity="center_vertical"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorTertiary" />
+ <ImageView
+ android:id="@+id/add_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_menu_add_field_holo_light"
+ android:paddingLeft="@dimen/editor_round_button_padding_left"
+ android:paddingRight="@dimen/editor_round_button_padding_right"
+ android:contentDescription="@string/description_plus_button" />
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/edit_date_picker.xml b/res/layout/edit_date_picker.xml
new file mode 100644
index 0000000..ca5e281
--- /dev/null
+++ b/res/layout/edit_date_picker.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<!-- Button to select a date in the contact editor. -->
+
+<Button
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/date_view"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="@dimen/editor_field_left_padding"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ style="@android:style/Widget.Holo.Light.Spinner" />
\ No newline at end of file
diff --git a/res/layout/edit_delete_button.xml b/res/layout/edit_delete_button.xml
new file mode 100644
index 0000000..f05b0e4
--- /dev/null
+++ b/res/layout/edit_delete_button.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+
+<!-- "Delete field" button in the contact editor. -->
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top">
+ <ImageView
+ android:id="@+id/delete_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:duplicateParentState="true"
+ android:background="?android:attr/selectableItemBackground"
+ android:src="@drawable/ic_menu_remove_field_holo_light"
+ android:paddingLeft="@dimen/editor_round_button_padding_left"
+ android:paddingRight="@dimen/editor_round_button_padding_right"
+ android:paddingTop="@dimen/editor_round_button_padding_top"
+ android:paddingBottom="@dimen/editor_round_button_padding_bottom"
+ android:contentDescription="@string/description_minus_button" />
+</FrameLayout>
\ No newline at end of file
diff --git a/res/layout/edit_divider.xml b/res/layout/edit_divider.xml
index eb2a49a..786bfca 100644
--- a/res/layout/edit_divider.xml
+++ b/res/layout/edit_divider.xml
@@ -16,6 +16,6 @@
<View xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="1dip"
android:background="?android:attr/listDivider"
/>
diff --git a/res/layout/edit_expansion_view.xml b/res/layout/edit_expansion_view.xml
new file mode 100644
index 0000000..96fe8de
--- /dev/null
+++ b/res/layout/edit_expansion_view.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+
+<!-- "More" or "less" expansion button in the contact editor. -->
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top">
+ <ImageView
+ android:id="@+id/expansion_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:duplicateParentState="true"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingLeft="@dimen/editor_round_button_padding_left"
+ android:paddingRight="@dimen/editor_round_button_padding_right"
+ android:paddingTop="@dimen/editor_round_button_padding_top"
+ android:paddingBottom="@dimen/editor_round_button_padding_bottom" />
+</FrameLayout>
\ No newline at end of file
diff --git a/res/layout/edit_field_list.xml b/res/layout/edit_field_list.xml
new file mode 100644
index 0000000..ba715c7
--- /dev/null
+++ b/res/layout/edit_field_list.xml
@@ -0,0 +1,26 @@
+<?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 to contain a list of fields in the contact editor. -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/editors"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/editor_field_left_padding"
+ android:orientation="vertical" />
\ No newline at end of file
diff --git a/res/layout/edit_field_title.xml b/res/layout/edit_field_title.xml
new file mode 100644
index 0000000..4918c4d
--- /dev/null
+++ b/res/layout/edit_field_title.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+
+<!-- Title of a field in the contact editor. -->
+
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/editor_field_top_padding"
+ android:paddingLeft="@dimen/editor_field_left_padding"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
\ No newline at end of file
diff --git a/res/layout/edit_spinner.xml b/res/layout/edit_spinner.xml
new file mode 100644
index 0000000..9e22ee7
--- /dev/null
+++ b/res/layout/edit_spinner.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<!-- Spinner for a field in the contact editor. -->
+
+<Spinner
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/spinner"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/editor_field_left_padding"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:paddingLeft="5dip"/>
\ No newline at end of file
diff --git a/res/layout/event_field_editor_view.xml b/res/layout/event_field_editor_view.xml
new file mode 100644
index 0000000..6625279
--- /dev/null
+++ b/res/layout/event_field_editor_view.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.
+-->
+
+<!-- Editor for a single event entry in the contact editor -->
+
+<com.android.contacts.editor.EventFieldEditorView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <include
+ android:id="@+id/title"
+ layout="@layout/edit_field_title" />
+
+ <include
+ android:id="@+id/spinner"
+ layout="@layout/edit_spinner"
+ android:visibility="gone" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:focusable="true"
+ android:clickable="true">
+
+ <include
+ android:id="@+id/date_view"
+ layout="@layout/edit_date_picker" />
+
+ <include
+ android:id="@+id/delete_button_container"
+ layout="@layout/edit_delete_button"
+ android:visibility="gone" />
+
+ </LinearLayout>
+
+</com.android.contacts.editor.EventFieldEditorView>
diff --git a/res/layout/external_raw_contact_editor_view.xml b/res/layout/external_raw_contact_editor_view.xml
index a964ce4..c524a74 100644
--- a/res/layout/external_raw_contact_editor_view.xml
+++ b/res/layout/external_raw_contact_editor_view.xml
@@ -51,7 +51,7 @@
android:background="@color/edit_divider"
/>
- <ImageView android:id="@+id/header_icon"
+ <ImageView android:id="@+id/account_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="7dip"
@@ -60,11 +60,11 @@
android:layout_below="@id/header_color_bar"
/>
- <TextView android:id="@+id/header_account_type"
+ <TextView android:id="@+id/account_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_toRightOf="@+id/header_icon"
- android:layout_alignTop="@id/header_icon"
+ android:layout_toRightOf="@+id/account_icon"
+ android:layout_alignTop="@id/account_icon"
android:layout_marginTop="-4dip"
android:textSize="24sp"
@@ -72,11 +72,11 @@
android:singleLine="true"
/>
- <TextView android:id="@+id/header_account_name"
+ <TextView android:id="@+id/account_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_toRightOf="@+id/header_icon"
- android:layout_alignBottom="@+id/header_icon"
+ android:layout_toRightOf="@+id/account_icon"
+ android:layout_alignBottom="@+id/account_icon"
android:layout_marginBottom="2dip"
android:textAppearance="?android:attr/textAppearanceSmall"
diff --git a/res/layout/group_browse_list_fragment.xml b/res/layout/group_browse_list_fragment.xml
new file mode 100644
index 0000000..50c02c8
--- /dev/null
+++ b/res/layout/group_browse_list_fragment.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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <ListView
+ android:id="@+id/list"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:fastScrollEnabled="true"
+ android:scrollbarStyle="outsideOverlay"
+ android:layout_weight="1" />
+
+ <TextView
+ android:id="@+id/empty"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:text="@string/noGroups"
+ android:visibility="gone"/>
+
+</LinearLayout>
diff --git a/res/layout/group_browse_list_item.xml b/res/layout/group_browse_list_item.xml
new file mode 100644
index 0000000..accbedd
--- /dev/null
+++ b/res/layout/group_browse_list_item.xml
@@ -0,0 +1,60 @@
+<?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:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:scaleType="center"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_gravity="center_vertical" />
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingTop="5dip"
+ android:paddingBottom="5dip">
+
+ <TextView
+ android:id="@+id/label"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:gravity="center_vertical"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:ellipsize="end"
+ android:singleLine="true" />
+
+ <TextView
+ android:id="@+id/account"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:gravity="center_vertical"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"
+ android:ellipsize="end"
+ android:singleLine="true"
+ android:textStyle="italic" />
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/res/layout/recent_calls.xml b/res/layout/group_browser_activity.xml
similarity index 62%
copy from res/layout/recent_calls.xml
copy to res/layout/group_browser_activity.xml
index f054b70..f7187d9 100644
--- a/res/layout/recent_calls.xml
+++ b/res/layout/group_browser_activity.xml
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
+<!-- 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.
@@ -16,19 +16,13 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent"
->
- <ListView android:id="@android:id/list"
- android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <fragment
+ android:id="@+id/list_fragment"
+ class="com.android.contacts.group.GroupBrowseListFragment"
android:layout_height="match_parent"
- android:scrollbarStyle="outsideOverlay"
- />
-
- <TextView android:id="@android:id/empty"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:text="@string/recentCalls_empty"
- android:gravity="center"
- android:textAppearance="?android:attr/textAppearanceLarge"
/>
+
</FrameLayout>
diff --git a/res/layout/group_detail_activity.xml b/res/layout/group_detail_activity.xml
new file mode 100644
index 0000000..707a65c
--- /dev/null
+++ b/res/layout/group_detail_activity.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <fragment
+ class="com.android.contacts.group.GroupDetailFragment"
+ android:id="@+id/group_detail_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</FrameLayout>
diff --git a/res/layout/group_detail_fragment.xml b/res/layout/group_detail_fragment.xml
new file mode 100644
index 0000000..70d67b6
--- /dev/null
+++ b/res/layout/group_detail_fragment.xml
@@ -0,0 +1,29 @@
+<?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:id="@+id/group_detail"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ListView
+ android:id="@+id/member_list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:scrollbarStyle="outsideOverlay"/>
+
+</LinearLayout>
diff --git a/res/layout/item_group_membership.xml b/res/layout/item_group_membership.xml
index 65730d4..cdf4e8a 100644
--- a/res/layout/item_group_membership.xml
+++ b/res/layout/item_group_membership.xml
@@ -21,11 +21,6 @@
android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="vertical">
- <View
- android:layout_width="match_parent"
- android:layout_height="1px"
- android:background="?android:attr/listDivider" />
-
<LinearLayout
android:id="@+id/kind_header"
android:layout_width="match_parent"
diff --git a/res/layout/item_kind_section.xml b/res/layout/item_kind_section.xml
index fdb55c9..6c6f960 100644
--- a/res/layout/item_kind_section.xml
+++ b/res/layout/item_kind_section.xml
@@ -4,9 +4,9 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
-
+
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -20,59 +20,22 @@
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:paddingBottom="@dimen/editor_field_bottom_padding"
android:orientation="vertical">
<View
android:layout_width="match_parent"
- android:layout_height="1px"
- android:background="?android:attr/listDivider" />
-
- <LinearLayout
- android:id="@+id/kind_header"
- android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_marginLeft="14dip"
- android:layout_marginTop="2dip"
- android:layout_marginBottom="2dip"
- android:layout_marginRight="?android:attr/scrollbarSize"
- android:orientation="horizontal"
- android:gravity="center_vertical"
- android:focusable="true"
- android:clickable="true">
-
- <TextView
- android:id="@+id/kind_title"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="@color/kind_title"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal" />
-
- <ImageButton
- android:id="@+id/kind_plus"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:duplicateParentState="true"
- android:background="?android:attr/selectableItemBackground"
- android:src="@drawable/ic_menu_add_field_holo_light"
- android:paddingLeft="@dimen/editor_round_button_padding_left"
- android:paddingRight="@dimen/editor_round_button_padding_right"
- android:paddingTop="@dimen/editor_round_button_padding_top"
- android:paddingBottom="@dimen/editor_round_button_padding_bottom"
- android:contentDescription="@string/description_plus_button" />
-
- </LinearLayout>
+ android:background="@drawable/divider_horizontal_light" />
<LinearLayout
android:id="@+id/kind_editors"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingBottom="6dip"
android:orientation="vertical" />
-</com.android.contacts.editor.KindSectionView>
+ <include
+ android:id="@+id/add_field_footer"
+ layout="@layout/edit_add_field" />
+
+</com.android.contacts.editor.KindSectionView>
\ No newline at end of file
diff --git a/res/layout/item_photo_editor.xml b/res/layout/item_photo_editor.xml
index 642908e..3590963 100644
--- a/res/layout/item_photo_editor.xml
+++ b/res/layout/item_photo_editor.xml
@@ -27,7 +27,7 @@
android:src="@drawable/ic_contact_picture"
android:cropToPadding="true"
android:scaleType="centerCrop"
- android:gravity="center"
+ android:gravity="left"
/>
<View
android:id="@+id/frame"
diff --git a/res/layout/list_section.xml b/res/layout/list_section.xml
index e920673..5265f88 100644
--- a/res/layout/list_section.xml
+++ b/res/layout/list_section.xml
@@ -18,8 +18,7 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="25dip"
- android:background="@drawable/section_header"
+ android:layout_height="@dimen/list_section_height"
>
<TextView
android:id="@+id/header_text"
diff --git a/res/layout/list_separator.xml b/res/layout/list_separator.xml
index 1257935..9f562cf 100644
--- a/res/layout/list_separator.xml
+++ b/res/layout/list_separator.xml
@@ -17,6 +17,5 @@
<!-- Layout used for list separators. -->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
style="?android:attr/listSeparatorTextViewStyle"
- android:textColor="@*android:color/dim_foreground_dark"
android:gravity="left|center_vertical"
/>
diff --git a/res/layout/phonetic_name_editor_view.xml b/res/layout/phonetic_name_editor_view.xml
new file mode 100644
index 0000000..832ca2c
--- /dev/null
+++ b/res/layout/phonetic_name_editor_view.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.
+-->
+
+<com.android.contacts.editor.PhoneticNameEditorView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="@dimen/editor_field_bottom_padding"
+ android:orientation="vertical">
+
+ <include
+ android:id="@+id/spinner"
+ layout="@layout/edit_spinner"
+ android:visibility="gone" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:focusable="true"
+ android:clickable="true">
+
+ <include
+ android:id="@+id/editors"
+ layout="@layout/edit_field_list" />
+
+ <include
+ android:id="@+id/expansion_view_container"
+ layout="@layout/edit_expansion_view"
+ android:visibility="gone" />
+
+ <include
+ android:id="@+id/delete_button_container"
+ layout="@layout/edit_delete_button"
+ android:visibility="gone" />
+
+ </LinearLayout>
+
+</com.android.contacts.editor.PhoneticNameEditorView>
diff --git a/res/layout/quickcontact.xml b/res/layout/quickcontact.xml
index a74424c..e2b291c 100644
--- a/res/layout/quickcontact.xml
+++ b/res/layout/quickcontact.xml
@@ -1,3 +1,4 @@
+<?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");
@@ -12,13 +13,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<view
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- class="com.android.contacts.quickcontact.QuickContactRootLayout"
- android:id="@+id/root"
- android:layout_width="match_parent"
+ android:id="@android:id/content"
+ android:layout_width="@dimen/quick_contact_width"
android:layout_height="wrap_content"
+ android:visibility="invisible"
android:orientation="vertical">
<FrameLayout
@@ -133,4 +133,4 @@
android:text="@string/quickcontact_clear_defaults_button" />
</LinearLayout>
</FrameLayout>
-</view>
+</LinearLayout>
diff --git a/res/layout/quickcontact_activity.xml b/res/layout/quickcontact_activity.xml
new file mode 100644
index 0000000..aced4a8
--- /dev/null
+++ b/res/layout/quickcontact_activity.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.
+-->
+<view
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ class="com.android.contacts.quickcontact.FloatingChildLayout"
+ android:id="@+id/floating_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:descendantFocusability="afterDescendants">
+
+ <include layout="@layout/quickcontact" />
+
+</view>
diff --git a/res/layout/quickcontact_default_item.xml b/res/layout/quickcontact_default_item.xml
index 25b6910..3a918f0 100755
--- a/res/layout/quickcontact_default_item.xml
+++ b/res/layout/quickcontact_default_item.xml
@@ -28,13 +28,13 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
- android:textAppearance="?android:attr/textAppearanceMediumInverse" />
+ android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@android:id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="-4dip"
- android:textAppearance="?android:attr/textAppearanceSmallInverse" />
+ android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
diff --git a/res/layout/quickcontact_resolve_item.xml b/res/layout/quickcontact_resolve_item.xml
index 55de80e..2805722 100755
--- a/res/layout/quickcontact_resolve_item.xml
+++ b/res/layout/quickcontact_resolve_item.xml
@@ -28,13 +28,13 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
- android:textAppearance="?android:attr/textAppearanceMediumInverse" />
+ android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@android:id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="-4dip"
- android:textAppearance="?android:attr/textAppearanceSmallInverse" />
+ android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
diff --git a/res/layout/raw_contact_editor_view.xml b/res/layout/raw_contact_editor_view.xml
index 62d904f..5aa1e95 100644
--- a/res/layout/raw_contact_editor_view.xml
+++ b/res/layout/raw_contact_editor_view.xml
@@ -21,89 +21,80 @@
android:orientation="vertical"
>
- <!-- Account info header -->
- <RelativeLayout android:id="@+id/header"
- android:layout_height="64dip"
- android:layout_width="match_parent"
- android:background="@android:drawable/list_selector_background"
- >
-
- <ImageView android:id="@+id/header_color_bar"
- android:layout_width="match_parent"
- android:layout_height="4dip"
- android:layout_marginBottom="5dip"
- android:background="@color/edit_divider"
- />
-
- <ImageView android:id="@+id/header_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="7dip"
- android:layout_marginRight="7dip"
- android:layout_centerVertical="true"
- android:layout_below="@id/header_color_bar"
- />
-
- <TextView android:id="@+id/header_account_type"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@+id/header_icon"
- android:layout_alignTop="@id/header_icon"
- android:layout_marginTop="-4dip"
-
- android:textSize="24sp"
- android:textColor="?android:attr/textColorPrimary"
- android:singleLine="true"
- />
-
- <TextView android:id="@+id/header_account_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@+id/header_icon"
- android:layout_alignBottom="@+id/header_icon"
- android:layout_marginBottom="2dip"
-
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorPrimary"
- android:singleLine="true"
- />
-
- <View
- android:layout_width="match_parent"
- android:layout_height="1px"
- android:layout_alignParentBottom="true"
-
- android:background="?android:attr/listDivider"
- />
- </RelativeLayout>
-
<LinearLayout
android:id="@+id/body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
- <FrameLayout
- android:id="@+id/stub_photo"
- android:layout_width="match_parent"
+ <LinearLayout
+ android:id="@+id/anchor_for_account_switcher"
android:layout_height="wrap_content"
- android:paddingLeft="12dip"
- android:paddingTop="10dip">
+ android:layout_width="match_parent"
+ android:layout_marginRight="4dip"
+ android:background="@android:drawable/list_selector_background"
+ android:orientation="horizontal"
+ android:gravity="left|center_vertical">
- <include
- android:id="@+id/edit_photo"
- layout="@layout/item_photo_editor" />
+ <FrameLayout
+ android:id="@+id/stub_photo"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
- </FrameLayout>
+ <include
+ android:id="@+id/edit_photo"
+ layout="@layout/item_photo_editor" />
- <com.android.contacts.editor.TextFieldsEditorView
+ </FrameLayout>
+
+ <LinearLayout
+ android:id="@+id/account"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:paddingLeft="@dimen/account_selector_horizontal_margin"
+ android:paddingRight="@dimen/account_selector_horizontal_margin"
+ android:background="@color/account_selection_background"
+ android:orientation="vertical"
+ android:gravity="left|center_vertical">
+ <TextView
+ android:id="@+id/account_type"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="20sp"
+ android:textColor="?android:attr/textColorPrimaryInverse"
+ android:singleLine="true" />
+
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:orientation="horizontal"
+ android:gravity="center_vertical">
+
+ <TextView
+ android:id="@+id/account_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorPrimaryInverse"
+ android:singleLine="true" />
+
+ <ImageView
+ android:id="@+id/account_icon"
+ android:layout_width="@dimen/account_selector_icon_size"
+ android:layout_height="@dimen/account_selector_icon_size" />
+ </LinearLayout>
+ </LinearLayout>
+ </LinearLayout>
+
+
+ <include
android:id="@+id/edit_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingRight="?android:attr/scrollbarSize"
- android:layout_below="@id/stub_photo"
- android:layout_marginTop="6dip"
- android:layout_marginBottom="4dip" />
+ layout="@layout/structured_name_editor_view" />
+
+ <include
+ android:id="@+id/edit_phonetic_name"
+ layout="@layout/phonetic_name_editor_view" />
<ViewStub android:id="@+id/aggregation_suggestion_stub"
android:inflatedId="@+id/aggregation_suggestion"
diff --git a/res/layout/social_widget.xml b/res/layout/social_widget.xml
index fb02bb7..ddcd995 100644
--- a/res/layout/social_widget.xml
+++ b/res/layout/social_widget.xml
@@ -14,75 +14,78 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="96dip"
android:background="#00000000"
- android:paddingLeft="12dip"
android:paddingTop="1dip"
- android:paddingRight="12dip"
- android:paddingBottom="20dip"
->
- <FrameLayout
- android:layout_width="70dip"
- android:layout_height="70dip"
- android:layout_marginTop="1dip"
- android:layout_marginLeft="1dip"
- >
- <ImageView
- android:id="@+id/image"
- android:padding="4dip"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
- <ImageButton
- android:id="@+id/border"
- android:background="@drawable/frame_thumbnail_contact_widget_holo"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- </FrameLayout>
- <RelativeLayout
- android:layout_width="0dip"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:background="@drawable/bg_status_contact_widget"
- android:layout_marginTop="4dip"
- android:layout_marginRight="4dip"
- android:layout_marginBottom="7dip"
- android:layout_marginLeft="0dip"
- android:paddingLeft="47dip"
- android:paddingRight="8dip"
- android:paddingTop="3dip"
- android:paddingBottom="6dip">
-
- <TextView
- android:id="@+id/name_and_snippet"
- android:layout_width="match_parent"
+ android:paddingBottom="20dip">
+ <LinearLayout
+ android:id="@+id/widget_container"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <FrameLayout
+ android:layout_width="70dip"
+ android:layout_height="70dip"
+ android:layout_marginTop="1dip"
+ android:layout_marginLeft="13dip">
+ <ImageView
+ android:id="@+id/image"
+ android:padding="4dip"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+ <ImageButton
+ android:id="@+id/border"
+ android:background="@drawable/frame_thumbnail_contact_widget_holo"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+ </FrameLayout>
+ <RelativeLayout
+ android:id="@+id/name_and_snippet_container"
+ android:layout_width="0dip"
android:layout_height="match_parent"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- android:maxLines="3"
- android:lineSpacingExtra="2sp"
- android:textColor="#FFFFFFFF"
- android:textSize="@dimen/widget_text_size_snippet" />
+ android:layout_weight="1"
+ android:background="@drawable/bg_status_contact_widget"
+ android:layout_marginTop="4dip"
+ android:layout_marginRight="16dip"
+ android:layout_marginBottom="7dip"
+ android:layout_marginLeft="0dip"
+ android:paddingLeft="47dip"
+ android:paddingRight="8dip"
+ android:paddingTop="3dip"
+ android:paddingBottom="6dip">
- <TextView
- android:id="@+id/name"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:textColor="#FFFFFFFF"
- android:textSize="@dimen/widget_text_size_name" />
+ <TextView
+ android:id="@+id/name_and_snippet"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:maxLines="3"
+ android:lineSpacingExtra="2sp"
+ android:textColor="#FFFFFFFF"
+ android:textSize="@dimen/widget_text_size_snippet" />
- <TextView
- android:id="@+id/status_date"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentBottom="true"
- android:background="@drawable/statusbox_attribute_holo"
- android:textSize="13sp"
- android:textColor="#FF444444"
- android:visibility="gone" />
- </RelativeLayout>
-</LinearLayout>
+ <TextView
+ android:id="@+id/name"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:textColor="#FFFFFFFF"
+ android:textSize="@dimen/widget_text_size_name" />
+
+ <TextView
+ android:id="@+id/status_date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentBottom="true"
+ android:background="@drawable/statusbox_attribute_holo"
+ android:textSize="13sp"
+ android:textColor="#FF444444"
+ android:visibility="gone" />
+ </RelativeLayout>
+ </LinearLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/res/layout/structured_name_editor_view.xml b/res/layout/structured_name_editor_view.xml
new file mode 100644
index 0000000..83efa6f
--- /dev/null
+++ b/res/layout/structured_name_editor_view.xml
@@ -0,0 +1,56 @@
+<?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.
+-->
+
+<com.android.contacts.editor.StructuredNameEditorView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <include
+ android:id="@+id/divider"
+ layout="@layout/edit_divider" />
+
+ <include
+ android:id="@+id/spinner"
+ layout="@layout/edit_spinner"
+ android:visibility="gone" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ android:focusable="true"
+ android:clickable="true">
+
+ <include
+ android:id="@+id/editors"
+ layout="@layout/edit_field_list" />
+
+ <include
+ android:id="@+id/expansion_view_container"
+ layout="@layout/edit_expansion_view"
+ android:visibility="gone" />
+
+ <include
+ android:id="@+id/delete_button_container"
+ layout="@layout/edit_delete_button"
+ android:visibility="gone" />
+
+ </LinearLayout>
+
+</com.android.contacts.editor.StructuredNameEditorView>
diff --git a/res/layout/text_fields_editor_view.xml b/res/layout/text_fields_editor_view.xml
new file mode 100644
index 0000000..d33e804
--- /dev/null
+++ b/res/layout/text_fields_editor_view.xml
@@ -0,0 +1,57 @@
+<?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.
+-->
+
+<com.android.contacts.editor.TextFieldsEditorView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <include
+ android:id="@+id/title"
+ layout="@layout/edit_field_title" />
+
+ <include
+ android:id="@+id/spinner"
+ layout="@layout/edit_spinner"
+ android:visibility="gone" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:focusable="true"
+ android:clickable="true">
+
+ <include
+ android:id="@+id/editors"
+ layout="@layout/edit_field_list" />
+
+ <include
+ android:id="@+id/expansion_view_container"
+ layout="@layout/edit_expansion_view"
+ android:visibility="gone" />
+
+ <include
+ android:id="@+id/delete_button_container"
+ layout="@layout/edit_delete_button"
+ android:visibility="gone" />
+
+ </LinearLayout>
+
+</com.android.contacts.editor.TextFieldsEditorView>
diff --git a/res/menu/list.xml b/res/menu/list.xml
index 2b3f453..56d92f8 100644
--- a/res/menu/list.xml
+++ b/res/menu/list.xml
@@ -27,9 +27,9 @@
android:alphabeticShortcut="n" />
<item
- android:id="@+id/menu_display_groups"
- android:icon="@*android:drawable/ic_menu_allfriends"
- android:title="@string/menu_displayGroup" />
+ android:id="@+id/menu_settings"
+ android:icon="@drawable/ic_menu_settings_holo_light"
+ android:title="@string/menu_settings" />
<item
android:id="@+id/menu_accounts"
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index e5b4839..313bcfe 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"افتراضي"</string>
<string name="removePhoto" msgid="4898105274130284565">"إزالة الصور"</string>
<string name="noContacts" msgid="8579310973261953559">"لا توجد جهات اتصال."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"لم يتم العثور على أية جهات اتصال متطابقة."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"ليس هناك جهات اتصال تشتمل على أرقام هواتف."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"جهات الاتصال فقط التي بها صور"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"جهة اتصال واحدة بها رقم هاتف"</item>
<item quantity="other" msgid="3299954047880968205">"<xliff:g id="COUNT">%d</xliff:g> من جهات الاتصال التي تشتمل على أرقام هواتف"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"ليس هناك جهات اتصال مرئية تشتمل على أرقام هواتف"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"ليس هناك جهات اتصال تشتمل على أرقام هواتف"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"جهة اتصال واحدة"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> من جهات الاتصال"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"ليس هناك جهات اتصال مرئية"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"لا توجد جهات اتصال"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"ليس هناك جهات اتصال مرئية"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"ليس هناك أية جهات اتصال مميزة بنجمة"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"ليس هناك جهات اتصال في <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"تم العثور على جهة اتصال واحدة"</item>
<item quantity="other" msgid="3852668542926965042">"تم العثور على <xliff:g id="COUNT">%d</xliff:g>"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"تم العثور على <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"جهات الاتصال"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"المفضلة"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"الهاتف"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"سجل المكالمات"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"سجل المكالمات فارغ."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"محو سجل المكالمات"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"هل أنت متأكد من أنك تريد محو سجل المكالمات؟"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"جارٍ محو سجل المكالمات"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"البريد الصوتي"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"صورة جهة الاتصال"</string>
<string name="description_minus_button" msgid="387136707700230172">"علامة الطرح"</string>
<string name="description_plus_button" msgid="515164827856229880">"علامة زائد"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"وحدة تخزين USB غير متوفرة"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"وحدة التخزين غير متوفرة."</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"لا بطاقة SD"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"لم يتم اكتشاف وحدة تخزين USB"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"لم يتم اكتشاف أية وحدة تخزين."</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"لم يتم اكتشاف بطاقة SD"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"البحث عن vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"استيراد من بطاقة SIM"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"استيراد من وحدة تخزين USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"استيراد من وحدة التخزين"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"استيراد من بطاقة SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"تصدير إلى وحدة تخزين USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"تصدير إلى وحدة التخزين"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"تصدير إلى بطاقة SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"مشاركة جهات الاتصال المرئية"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"استيراد ملف vCard واحد"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"استيراد ملفات vCard متعددة"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"استيراد جميع ملفات vCard"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"البحث عن بيانات vCard في وحدة تخزين USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"جارٍ البحث عن بيانات vCard في وحدة التخزين."</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"البحث عن بيانات vCard على بطاقة SD"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"أخفق فحص وحدة تخزين USB"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"أخفق فحص وحدة التخزين."</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"أخفق المسح الضوئي لبطاقة SD"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"أخفق فحص وحدة تخزين USB (السبب: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"أخفق فحص وحدة التخزين (السبب: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")."</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"أخفق المسح الضوئي لبطاقة SD (السبب: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"خطأ I/O"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"الذاكرة لا تكفي (ربما يكون الملف كبير جدًا)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"أخفق تحليل vCard بسبب غير متوقع"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"التنسيق غير معتمد."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"أخفق استيراد vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"لم يتم العثور على ملف vCard على وحدة تخزين USB"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"لم يتم العثور على أي ملف vCard في وحدة التخزين."</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"لم يتم العثور على ملف vCard على بطاقة SD"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"أخفق جمع معلومات وصفية عن ملفات vCard المحددة"</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"أخفق استيراد ملف أو أكثر (%s)."</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"أخفق تصدير بيانات جهة الاتصال"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"أخفق تصدير بيانات جهة الاتصال."\n"سبب الإخفاق: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"ليس هناك جهة اتصال قابلة للتصدير"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"هناك ملفات vCard كثيرة جدًا في وحدة تخزين USB"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"هناك عدد أكبر مما يجب من ملفات vCard في وحدة التخزين."</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"هناك ملفات vCard كثيرة جدًا على بطاقة SD"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"اسم الملف المطلوب طويل جدًا (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"تم الانتهاء من تصدير <xliff:g id="FILENAME">%s</xliff:g>"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"الاسم الصوتي الممنوح"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"الاسم الصوتي الأوسط"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"اسم الأسرة الصوتي"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"الاسم"</string>
<string name="account_type_format" msgid="718948015590343010">"جهة اتصال <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
- <string name="from_account_format" msgid="687567483928582084">"من <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"استخدام هذه الصورة"</string>
<string name="contact_read_only" msgid="1203216914575723978">"معلومات جهة اتصال <xliff:g id="SOURCE">%1$s</xliff:g> غير قابلة للتعديل على هذا الجهاز."</string>
<string name="no_contact_details" msgid="6754415338321837001">"ليس هناك معلومات إضافية لجهة الاتصال هذه"</string>
@@ -423,13 +427,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"إزالة بعض التطبيقات"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"إعادة محاولة الترقية"</string>
<string name="search_results_searching" msgid="7755623475227227314">"جارِ البحث..."</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"عرض العناصر المحددة"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"عرض الكل"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"تحديد الكل"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"إلغاء تحديد الكل"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"لم يتم تحديد جهات اتصال."</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"عرض العناصر المحددة"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"عرض الكل"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"تحديد الكل"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"إلغاء تحديد الكل"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"تم تحديد متلقٍ واحد"</item>
+ <item quantity="other" msgid="4608837420986126229">"تم تحديد <xliff:g id="COUNT">%d</xliff:g> من المستلمين"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"لم يتم تحديد جهات اتصال."</string>
<string name="add_field" msgid="2384260056674995230">"إضافة حقل آخر"</string>
+ <string name="add_phone" msgid="4421904942555210013">"إضافة رقم هاتف جديد"</string>
+ <string name="add_email" msgid="175079666329862215">"إضافة بريد إلكتروني جديد"</string>
+ <string name="add_im" msgid="5158094627521120439">"إضافة حساب مراسلة فورية جديد"</string>
+ <string name="add_address" msgid="418292312672970688">"إضافة عنوان جديد"</string>
+ <string name="add_note" msgid="2753771325725383279">"إضافة ملاحظة جديدة"</string>
+ <string name="add_website" msgid="4312391288948517344">"إضافة موقع إلكتروني جديد"</string>
+ <string name="add_event" msgid="7488781591843886426">"إضافة حدث جديد"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"إضافة علاقة جديدة"</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>
<string name="description_star" msgid="2605854427360036550">"مفضل"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 4f5bf9f..d18e39d 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"По подразбиране"</string>
<string name="removePhoto" msgid="4898105274130284565">"Премахване на снимката"</string>
<string name="noContacts" msgid="8579310973261953559">"Няма контакти."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Не са намерени съответстващи контакти."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Няма контакти с тел. номера."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Само контакти с тел. номера"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"1 контакт с телефонен номер"</item>
<item quantity="other" msgid="3299954047880968205">"<xliff:g id="COUNT">%d</xliff:g> контакта с телефонни номера"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Няма видими контакти с телефонни номера"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Няма контакти с телефонни номера"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 контакт"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> контакта"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Няма видими контакти"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Няма контакти"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Няма видими контакти"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Няма контакти със звезда"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Няма контакти във: <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"1 намерен"</item>
<item quantity="other" msgid="3852668542926965042">"<xliff:g id="COUNT">%d</xliff:g> намерени"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> намерени"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Контакти"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Любими"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Телефон"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Списък на обажданията"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Списъкът на обажданията е празен."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Изчистване на списъка с обажданията"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Наистина ли искате да изчистите списъка на обажданията?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Списъкът с обажданията се изчиства"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Гласова поща"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"снимка на контакта"</string>
<string name="description_minus_button" msgid="387136707700230172">"минус"</string>
<string name="description_plus_button" msgid="515164827856229880">"плюс"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Не е налице USB хранилище"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Няма хранилище"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Няма SD карта"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Няма USB хранилище"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Не бе открито хранилище"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Не е открита SD карта"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Търсене на vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Импортиране от SIM карта"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Импорт. от USB хранилище"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Импорт. от хранилището"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Импортиране от SD карта"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Експорт. в USB хранилище"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Експорт. в хранилището"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Експортиране в SD карта"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Споделяне на видимите контакти"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Импортиране на един vCard файл"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Импортиране на няколко vCard файла"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Импортиране на всички vCard файлове"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Търсят се данни за vCard в USB хранилището"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Търсят се данни за vCard в хранилището"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Търсене на vCard данни в SD картата"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Сканирането на USB хранилището не бе успешно"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Сканирането на хранилището не бе успешно"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Неуспешно сканиране на SD карта"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Сканирането на USB хранилището не бе успешно (Причина: „<xliff:g id="FAIL_REASON">%s</xliff:g>“)"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Сканирането на хранилището не бе успешно (Причина: „<xliff:g id="FAIL_REASON">%s</xliff:g>“)"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Неуспешно сканиране на SD карта ( Причина: „<xliff:g id="FAIL_REASON">%s</xliff:g>“)"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"I/O грешка"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Няма достатъчно памет (файлът може да е твърде голям)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Неуспешен анализ на vCard по неизвестна причина"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Форматът не се поддържа."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Импортирането на vCard не бе успешно"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"В USB устройството за съхранение не бе намерен vCard файл"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"В хранилището не бе намерен vCard файл"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"На SD картата не бе намерен vCard файл"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Събирането на метаинформация от дадените vCard файлове не бе успешно."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Неуспешно импортиране на един или повече файлове (%s)."</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Неуспешно експортиране на данни за контакти"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Неуспешно експортиране на данни за контакти."\n"Причина: „<xliff:g id="FAIL_REASON">%s</xliff:g>“"</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Няма контакт за експортиране"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"В USB хранилището има твърде много vCard файлове"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Твърде много vCard файлове в хранилището"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Твърде много vCard файлове на SD картата"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Изисканото име на файла е твърде дълго („<xliff:g id="FILENAME">%s</xliff:g>“)"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Експортирането на <xliff:g id="FILENAME">%s</xliff:g> завърши"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Собствено име, както се произнася"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Презиме, както се произнася"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Фамилия, както се произнася"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Име, както се произнася"</string>
<string name="account_type_format" msgid="718948015590343010">"Контакт от <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
- <string name="from_account_format" msgid="687567483928582084">"от <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Използване на тази снимка"</string>
<string name="contact_read_only" msgid="1203216914575723978">"Информацията за контакта от <xliff:g id="SOURCE">%1$s</xliff:g> не може да бъде редактирана на това устройство."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Няма допълнителна информация за този контакт"</string>
@@ -423,13 +427,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Деинсталиране на някои приложения"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Повторен опит за надстройка"</string>
<string name="search_results_searching" msgid="7755623475227227314">"Търси се..."</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"Показване на избраните"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"Показване на всички"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"Избиране на всичко"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"Премахване на избора от всички"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"Няма избрани контакти."</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"Показване на избраните"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"Показване на всички"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"Избиране на всички"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"Премахване на избора от всички"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"Избран е 1 получател"</item>
+ <item quantity="other" msgid="4608837420986126229">"<xliff:g id="COUNT">%d</xliff:g> избрани получатели"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"Няма избрани контакти."</string>
<string name="add_field" msgid="2384260056674995230">"Добавяне на друго поле"</string>
+ <string name="add_phone" msgid="4421904942555210013">"+ Нов телефонен номер"</string>
+ <string name="add_email" msgid="175079666329862215">"+ Нов имейл"</string>
+ <string name="add_im" msgid="5158094627521120439">"+ Нов профил за чат"</string>
+ <string name="add_address" msgid="418292312672970688">"+ Нов адрес"</string>
+ <string name="add_note" msgid="2753771325725383279">"+ Нова бележка"</string>
+ <string name="add_website" msgid="4312391288948517344">"+ Нов уебсайт"</string>
+ <string name="add_event" msgid="7488781591843886426">"+ Ново събитие"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"+ Ново взаимоотношение"</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>
<string name="description_star" msgid="2605854427360036550">"любимо"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index d8d726c..5d78297 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -72,7 +72,7 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"Fonètic"</string>
<string name="label_notes" msgid="8337354953278341042">"Notes"</string>
<string name="label_sip_address" msgid="124073911714324974">"Trucada per Internet"</string>
- <string name="label_ringtone" msgid="8833166825330686244">"So de trucada"</string>
+ <string name="label_ringtone" msgid="8833166825330686244">"To"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"Nom fonètic"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Empresa"</string>
<string name="ghostData_title" msgid="7496735200318496110">"Títol"</string>
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Predeterminat"</string>
<string name="removePhoto" msgid="4898105274130284565">"Elimina la foto"</string>
<string name="noContacts" msgid="8579310973261953559">"No hi ha contactes."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"No s\'ha trobat cap contacte coincident."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"No hi ha cap contacte amb número de telèfon."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Només els contactes amb telèfons"</string>
@@ -119,11 +121,10 @@
<item quantity="one" msgid="3405747744700823280">"1 contacte"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> contactes"</item>
</plurals>
- <string name="listTotalAllContactsZero" msgid="1889349925514589304">"No hi ha contactes"</string>
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"No hi ha cap contacte"</string>
<string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"No hi ha cap contacte visible"</string>
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"<xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"No hi ha cap contacte destacat"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"No hi ha cap contacte a <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"1 contacte"</item>
<item quantity="other" msgid="3852668542926965042">"<xliff:g id="COUNT">%d</xliff:g> contactes"</item>
@@ -135,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> contactes"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Contactes"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Preferits"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telèfon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Registre de trucades"</string>
@@ -150,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"El registre de trucades és buit."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Esborrament del registre de trucades"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Esteu segur que voleu esborrar el registre de trucades?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Esborrant el registre de trucada"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Correu de veu"</string>
@@ -209,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"foto del contacte"</string>
<string name="description_minus_button" msgid="387136707700230172">"menys"</string>
<string name="description_plus_button" msgid="515164827856229880">"més"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Emmag. USB no disp."</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Emmagatzematge no dispon."</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"No hi ha cap targeta SD"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Cap emmagatzematge USB detectat"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"No s\'ha detectat cap emmagatzematge"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"No s\'ha detectat cap targeta SD"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"S\'està cercant la vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Importa des de la targeta SIM"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Importa des de l\'emmagatzematge USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Importa de l\'emmagatzematge"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Importa des de la targeta SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Exporta a l\'emmagatzematge USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Exporta a emmagatzematge"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Exporta a la targeta SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Comparteix els contactes visibles"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Importa un fitxer vCard"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importa diversos fitxers vCard"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Importa tots els fitxers vCard"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"S\'estan cercant dades de vCard a l\'emmagatzematge USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"S\'estan cercant dades de vCard a l\'emmagatzematge"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"S\'estan cercant les dades de vCard a la targeta SD"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"S\'ha produït un error en escanejar l\'emmagatzematge USB"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"S\'ha produït un error en examinar l\'emmagatzematge"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"No s\'ha pogut explorar la targeta SD"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"S\'ha produït un error en escanejar l\'emmagatzematge USB (motiu: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"S\'ha produït un error en examinar l\'emmagatzematge (Motiu: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"No s\'ha pogut explorar la targeta SD (motiu: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Error d\'E/S"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"La memòria és insuficient (és possible que el fitxer sigui massa gran)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"No s\'ha pogut analitzar la vCard per un motiu inesperat"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"No s\'admet aquest format."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"No s\'ha pogut importar la vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"No s\'ha trobat cap fitxer vCard a l\'emmagatzematge USB"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"No s\'ha trobat cap fitxer vCard a l\'emmagatzematge"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"No s\'ha trobat cap fitxer vCard a la targeta SD"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"S\'ha produït un error en aplegar metainformació dels fitxers vCard especificats."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"No s\'ha pogut importar un o més fitxers (%s)."</string>
@@ -260,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"No s\'han pogut exportar les dades de contacte"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"No s\'han pogut exportar les dades de contacte."\n"Motiu de l\'error: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"No hi ha cap contacte que es pugui exportar"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Massa fitxers vCard a l\'emmagatzematge USB"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Hi ha massa fitxers vCard a l\'emmagatzematge"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Hi ha massa fitxers vCard a la targeta SD"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"El nom de fitxer obligatori és massa llarg (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Exportació de <xliff:g id="FILENAME">%s</xliff:g> finalitzada"</string>
@@ -398,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Nom fonètic"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Primer cognom fonètic"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Cognoms fonètics"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Nom fonètic"</string>
<string name="account_type_format" msgid="718948015590343010">"Contacte de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
- <string name="from_account_format" msgid="687567483928582084">"de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Utilitza aquesta foto"</string>
<string name="contact_read_only" msgid="1203216914575723978">"La informació de contacte de <xliff:g id="SOURCE">%1$s</xliff:g> no es pot editar en aquest dispositiu."</string>
<string name="no_contact_details" msgid="6754415338321837001">"No hi ha informació addicional per a aquest contacte"</string>
@@ -421,13 +427,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Desinstal·leu aplicacions"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Torna a provar d\'actualitzar"</string>
<string name="search_results_searching" msgid="7755623475227227314">"S\'està cercant..."</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"Mostra la selecció"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"Mostra-ho tot"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"Selecciona-ho tot"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"Anul·la tota la selecció"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"No s\'ha seleccionat cap contacte."</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"Mostra la selecció"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"Mostra-ho tot"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"Selecciona-ho tot"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"Anul·la tota la selecció"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"1 destinatari seleccionat"</item>
+ <item quantity="other" msgid="4608837420986126229">"<xliff:g id="COUNT">%d</xliff:g> destinataris seleccionats"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"No s\'ha seleccionat cap contacte."</string>
<string name="add_field" msgid="2384260056674995230">"Afegeix un altre camp"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Afegeix núm. tel. nou"</string>
+ <string name="add_email" msgid="175079666329862215">"Afegeix correu el. nou"</string>
+ <string name="add_im" msgid="5158094627521120439">"Afegeix compte MI nou"</string>
+ <string name="add_address" msgid="418292312672970688">"Afegeix adreça nova"</string>
+ <string name="add_note" msgid="2753771325725383279">"Afegeix nota nova"</string>
+ <string name="add_website" msgid="4312391288948517344">"Afegeix lloc web nou"</string>
+ <string name="add_event" msgid="7488781591843886426">"Afegeix esdevenim. nou"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Afegeix relació nova"</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>
<string name="description_star" msgid="2605854427360036550">"preferit"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 2737618..a346747 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Výchozí nastavení"</string>
<string name="removePhoto" msgid="4898105274130284565">"Odebrat fotografii"</string>
<string name="noContacts" msgid="8579310973261953559">"Žádné kontakty."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Nebyly nalezeny žádné odpovídající kontakty."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Ke kontaktům nejsou přiřazena žádná telefonní čísla."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Pouze kontakty s telefony"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"1 kontakt s telefonním číslem"</item>
<item quantity="other" msgid="3299954047880968205">"Počet kontaktů s telefonními čísly: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Žádné kontakty s telefonními čísly nejsou viditelné"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Ke kontaktům nejsou přiřazena žádná telefonní čísla"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 kontakt"</item>
<item quantity="other" msgid="3578469907265375314">"Počet kontaktů: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Žádné kontakty nejsou viditelné"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Žádné kontakty"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Žádné kontakty nejsou viditelné"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Žádné kontakty označené hvězdičkou"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Žádné kontakty v položce <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"Počet nalezených položek: 1"</item>
<item quantity="other" msgid="3852668542926965042">"Počet nalezených položek: <xliff:g id="COUNT">%d</xliff:g>"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"Počet nalezených položek: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Kontakty"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Oblíbené"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telefon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Hovory"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Záznam hovorů je prázdný."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Vymazat hovory"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Opravdu chcete vymazat hovory?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Vymazání hovorů"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Hlasová schránka"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"fotografie kontaktu"</string>
<string name="description_minus_button" msgid="387136707700230172">"mínus"</string>
<string name="description_plus_button" msgid="515164827856229880">"plus"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Úložiště USB nedostupné"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Úložiště je nedostupné"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Žádná karta SD"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Úložiště USB nenalezeno"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Nebylo nalezeno žádné úložiště"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Nebyla zjištěna žádná karta SD"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Vyhledávání karty vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Importovat z karty SIM"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Importovat z úložiště USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Importovat z úložiště"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Importovat z karty SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Export do úložiště USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Exportovat do úložiště"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Exportovat na kartu SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Sdílet viditelné kontakty"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Importovat jeden soubor vCard"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importovat několik souborů vCard"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Importovat všechny soubory vCard"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Vyhledávání dat karty vCard v úložišti USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Vyhledávání dat karty vCard v úložišti"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Vyhledávání dat karty vCard na kartě SD"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Vyhledávání v úložišti USB se nezdařilo"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Vyhledávání v úložišti se nezdařilo"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Vyhledávání na kartě SD se nezdařilo"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Vyhledávání v úložišti USB se nezdařilo (Důvod: „<xliff:g id="FAIL_REASON">%s</xliff:g>“)"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Vyhledávání v úložišti se nezdařilo (Důvod: <xliff:g id="FAIL_REASON">%s</xliff:g>)"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Vyhledávání na kartě SD se nezdařilo. (Důvod: <xliff:g id="FAIL_REASON">%s</xliff:g>)"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Chyba V/V"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Není k dispozici dostatek paměti (soubor může být příliš velký)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Analýza karty vCard se z neznámého důvodu nezdařila."</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Formát není podporován."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Import karty vCard se nezdařil"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"V úložišti USB nebyl nalezen žádný soubor vCard"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"V úložišti nebyl nalezen žádný soubor vCard"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Na kartě SD nebyl nalezen žádný soubor vCard"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Shromáždění metainformací zadaných souborů vCard se nezdařilo."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Import jednoho nebo více souborů se nezdařil (%s)."</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Export dat kontaktů se nezdařil"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Export dat kontaktů se nezdařil."\n"Příčina chyby: <xliff:g id="FAIL_REASON">%s</xliff:g>"</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Žádný kontakt nelze exportovat"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"V úložišti USB je příliš mnoho souborů vCard"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"V úložišti je příliš mnoho souborů vCard."</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Na kartě SD je příliš mnoho souborů vCard"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Požadovaný název souboru (<xliff:g id="FILENAME">%s</xliff:g>) je příliš dlouhý"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Export souboru <xliff:g id="FILENAME">%s</xliff:g> byl dokončen."</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Křestní jméno (foneticky)"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Druhé jméno (foneticky)"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Příjmení (foneticky)"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Jméno (foneticky)"</string>
<string name="account_type_format" msgid="718948015590343010">"Kontakt ze zdroje <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
- <string name="from_account_format" msgid="687567483928582084">"z účtu <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Použít tuto fotografii"</string>
<string name="contact_read_only" msgid="1203216914575723978">"Kontaktní informace ze zdroje <xliff:g id="SOURCE">%1$s</xliff:g> není možné na tomto zařízení upravit."</string>
<string name="no_contact_details" msgid="6754415338321837001">"U tohoto kontaktu nejsou uvedeny dodatečné informace"</string>
@@ -433,6 +437,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"Nevybrali jste žádné kontakty."</string>
<string name="add_field" msgid="2384260056674995230">"Přidat další pole"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Přidat nové tel. číslo"</string>
+ <string name="add_email" msgid="175079666329862215">"Přidat nový e-mail"</string>
+ <string name="add_im" msgid="5158094627521120439">"Přidat nový účet IM"</string>
+ <string name="add_address" msgid="418292312672970688">"Přidat novou adresu"</string>
+ <string name="add_note" msgid="2753771325725383279">"Přidat novou poznámku"</string>
+ <string name="add_website" msgid="4312391288948517344">"Přidat nový web"</string>
+ <string name="add_event" msgid="7488781591843886426">"Přidat novou událost"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Přidat nový vztah"</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>
<string name="description_star" msgid="2605854427360036550">"oblíbené"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 7cc317c..0c17939 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Standard"</string>
<string name="removePhoto" msgid="4898105274130284565">"Fjern billede"</string>
<string name="noContacts" msgid="8579310973261953559">"Der er ingen kontakter."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Der blev ikke fundet nogen matchende kontakter."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Der er ingen kontakter med telefonnumre."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Kun kontakter med telefoner"</string>
@@ -134,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> fundet"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Kontakter"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favorit"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telefon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Opk.liste"</string>
@@ -149,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Opkaldslisten er tom."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Ryd opkaldsliste"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Er du sikker på, at du vil rydde opkaldslisten?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Rydder opkaldsliste"</string>
<string name="imei" msgid="3045126336951684285">"IMEI-nummer"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Voicemail"</string>
@@ -208,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"kontaktpersonfoto"</string>
<string name="description_minus_button" msgid="387136707700230172">"minus"</string>
<string name="description_plus_button" msgid="515164827856229880">"plus"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"USB-lager utilgængeligt"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Lager ikke tilgængeligt"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Der er intet SD-kort"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Intet USB-lager blev fundet"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Intet lager fundet"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Der blev ikke fundet noget SD-kort"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Søger efter vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Importer fra SIM-kort"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Importer fra USB-lager"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Importer fra lager"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Importer fra SD-kort"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Eksporter til USB-lager"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Eksporter til lager"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Eksporter til SD-kort"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Del synlige kontaktpersoner"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Importer en VCard-fil"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importer flere VCard-filer"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Importer alle VCard-filer"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Søger efter vCard-data i USB-lager"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Søger efter vCard-data i lager"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Søger efter vCard-kort på SD-kortet"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Scanningen af USB-lager mislykkedes"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Scanning af lageret mislykkedes"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Scanningen af SD-kortet mislykkedes"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Scanningen af USB-lager mislykkedes (årsag: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Scanning af lager mislykkedes (Årsag: <xliff:g id="FAIL_REASON">%s</xliff:g>)"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Scanningen af SD-kortet mislykkedes: (Årsag: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"I/O-fejl"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Der er ikke nok hukommelse (filen er muligvis for stor)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"vCard kunne ikke parses pga. en uventet årsag"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Formatet understøttes ikke."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"vCard kunne ikke importeres"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"Der blev ikke fundet nogen vCard-fil i USB-lageret"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Der blev ikke fundet nogen vCard-fil i lageret"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Der blev ikke fundet nogen vCard-fil på SD-kortet"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Metaoplysninger om angivne vCard-filer kunne ikke hentes."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"En eller flere filer blev ikke importeret (%s)."</string>
@@ -259,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Eksport af kontaktdata mislykkedes"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Eksport af kontaktpersondata mislykkedes."\n"Årsag til fejl: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Der er ingen kontakter, der kan eksporteres"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Der er for mange vCard-filer i USB-lager"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Der er for mange vCard-filer i lageret"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Der er for mange vCard-data på SD-kortet"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Det krævede filnavn er for langt (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Eksport af <xliff:g id="FILENAME">%s</xliff:g> afsluttet"</string>
@@ -397,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Fonetisk fornavn"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetisk mellemnavn"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Fonetisk efternavn"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Fonetisk navn"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> kontaktperson"</string>
- <string name="from_account_format" msgid="687567483928582084">"fra<xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Brug dette billede"</string>
<string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g> kontaktoplysninger kan ikke redigeres på denne enhed."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Ingen yderligere oplysninger for denne kontakt"</string>
@@ -430,6 +437,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"Ingen kontaktpersoner er valgt."</string>
<string name="add_field" msgid="2384260056674995230">"Tilføj et felt mere"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Tilføj nyt telefonnr."</string>
+ <string name="add_email" msgid="175079666329862215">"Tilføj ny e-mail"</string>
+ <string name="add_im" msgid="5158094627521120439">"Tilføj ny IM-konto"</string>
+ <string name="add_address" msgid="418292312672970688">"Tilføj ny adresse"</string>
+ <string name="add_note" msgid="2753771325725383279">"Tilføj ny bemærkning"</string>
+ <string name="add_website" msgid="4312391288948517344">"Tilføj nyt websted"</string>
+ <string name="add_event" msgid="7488781591843886426">"Tilføj ny begivenhed"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Tilføj nyt forhold"</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>
<string name="description_star" msgid="2605854427360036550">"foretrukken"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index dfdeb1d..e1382f8 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -95,8 +95,10 @@
<string name="default_ringtone" msgid="9099988849649827972">"Standard"</string>
<string name="removePhoto" msgid="4898105274130284565">"Foto entfernen"</string>
<string name="noContacts" msgid="8579310973261953559">"Keine Kontakte"</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Keine passenden Kontakte gefunden"</string>
- <string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Keine Kontakte mit Telefonnummern"</string>
+ <string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Keine sichtbaren Kontakte mit Telefonnummern"</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Nur Kontakte mit Telefon"</string>
<string name="showFilterPhonesDescrip" msgid="6644443248815191067">"Nur Kontakte mit Telefonnummern anzeigen"</string>
<string name="headerContactGroups" msgid="2426134991932503843">"Kontakte zum Anzeigen auswählen"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"1 Kontakt mit Telefonnummer"</item>
<item quantity="other" msgid="3299954047880968205">"<xliff:g id="COUNT">%d</xliff:g> Kontakte mit Telefonnummern"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Keine sichtbaren Kontakte mit Telefonnummern"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Keine sichtbaren Kontakte mit Telefonnummern"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 Kontakt"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> Kontakte"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Keine sichtbaren Kontakte"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Keine Kontakte"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Keine sichtbaren Kontakte"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Keine markierten Kontakte"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Keine Kontakte in <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"1 gefunden"</item>
<item quantity="other" msgid="3852668542926965042">"<xliff:g id="COUNT">%d</xliff:g> gefunden"</item>
@@ -137,13 +136,15 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> gefunden"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Kontakte"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoriten"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telefon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Anrufe"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"Alle Kontakte"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"Markierte Kontakte"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"Kontakte mit Telefonnummern"</string>
- <string name="menu_sendTextMessage" msgid="6937343460284499306">"Textnachricht senden"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"SMS/MMS senden"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"<xliff:g id="NAME">%s</xliff:g> anrufen"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"Nr. vor Anruf bearbeiten"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"Zu Kontakten hinzufügen"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Anrufliste ist leer"</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Anrufprotokoll löschen"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Möchten Sie das Anrufprotokoll wirklich löschen?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Anrufprotokoll wird gelöscht."</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Mailbox"</string>
@@ -162,8 +164,8 @@
<string name="dialerDialpadHintText" msgid="5824490365898349041">"Nummer wählen"</string>
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"Ladevorgang von SIM-Karte läuft..."</string>
<string name="simContacts_title" msgid="27341688347689769">"Kontakte auf SIM-Karte"</string>
- <string name="noContactsHelpTextWithSyncForCreateShortcut" msgid="801504710275614594">"Sie haben keine Kontakte. Wenn Sie gerade ein Konto hinzugefügt haben, kann die Synchronisierung der Kontakte einige Minuten dauern."</string>
- <string name="noContactsHelpTextForCreateShortcut" msgid="3081286388667108335">"Sie haben keine Kontakte."</string>
+ <string name="noContactsHelpTextWithSyncForCreateShortcut" msgid="801504710275614594">"Es sind keine Kontakte vorhanden. Wenn Sie gerade ein Konto hinzugefügt haben, kann die Synchronisierung der Kontakte einige Minuten dauern."</string>
+ <string name="noContactsHelpTextForCreateShortcut" msgid="3081286388667108335">"Es sind keine Kontakte vorhanden."</string>
<string name="noContactsHelpText" product="tablet" msgid="6450346791169710787">"Es können keine Kontakte angezeigt werden."\n\n"Tippen Sie zum Hinzufügen von Kontakten auf "<font fgcolor="#ffffffff"><b>"Menü"</b></font>" und dann auf "\n" "\n<li><font fgcolor="#ffffffff"><b>"Konten"</b></font>", um ein Konto hinzuzufügen oder mit Kontakten für die Synchronisierung mit dem Tablet zu konfigurieren"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Neuer Kontakt"</b></font>", um einen Kontakt neu zu erstellen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Import/Export"</b></font>", um Kontakte von Ihrer SIM- oder SD-Karte zu importieren"\n</li></string>
<string name="noContactsHelpText" product="default" msgid="7633826236417884130">"Es können keine Kontakte angezeigt werden."\n\n"Tippen Sie zum Hinzufügen von Kontakten auf "<font fgcolor="#ffffffff"><b>"Menü"</b></font>" und dann auf "\n" "\n<li><font fgcolor="#ffffffff"><b>"Konten"</b></font>", um ein Konto hinzuzufügen oder mit Kontakten für die Synchronisierung mit dem Telefon zu konfigurieren"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Neuer Kontakt"</b></font>", um einen Kontakt neu zu erstellen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Import/Export"</b></font>", um Kontakte aus Ihrer SIM- oder SD-Karte zu importieren"\n</li></string>
<string name="noContactsHelpTextWithSync" product="tablet" msgid="2364665535969139880">"Es können keine Kontakte angezeigt werden. Wenn Sie gerade ein Konto hinzugefügt haben, kann die Kontaktsynchronisierung etwas dauern."\n\n"Zum Hinzufügen von Kontakten drücken Sie "<font fgcolor="#ffffffff"><b>"Menü"</b></font>" und tippen dann auf "\n" "\n<li><font fgcolor="#ffffffff"><b>"Konten"</b></font>", um ein Konto hinzuzufügen oder mit Kontakten für die Synchronisierung mit dem Tablet zu konfigurieren"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Anzeigeoptionen"</b></font>", um zu ändern, welche Kontakte angezeigt werden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Neuer Kontakt"</b></font>", um einen Kontakt neu zu erstellen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Import/Export"</b></font>", um Kontakte von Ihrer SIM- oder SD-Karte zu importieren"\n</li></string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"Kontaktbild"</string>
<string name="description_minus_button" msgid="387136707700230172">"minus"</string>
<string name="description_plus_button" msgid="515164827856229880">"plus"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"USB-Speicher nicht verfügbar"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Kein Speicher verfügbar"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Keine SD-Karte"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Keinen USB-Speicher gefunden"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Kein Speicher gefunden"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Keine SD-Karte gefunden"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"vCard wird gesucht."</string>
<string name="import_from_sim" msgid="3859272228033941659">"Von SIM-Karte importieren"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Aus USB-Speicher import."</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Aus Speicher importieren"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Von SD-Karte importieren"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"In USB-Speicher exportieren"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"In Speicher exportieren"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Auf SD-Karte exportieren"</string>
- <string name="share_visible_contacts" msgid="890150378880783797">"Sichtbare Kontakte weiterleiten"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Sichtbare Kontakte weitergeben"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Eine VCard-Datei importieren"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Mehrere VCard-Dateien importieren"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Alle VCard-Dateien importieren"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Suche nach vCard-Daten in USB-Speicher"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Suche nach vCard-Daten im Speicher..."</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Suche nach einer vCard-Information auf der SD-Karte"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Scannen des USB-Speichers fehlgeschlagen"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Scannen des Speichers fehlgeschlagen"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Fehler beim Lesen der SD-Karte"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Scannen des USB-Speichers fehlgeschlagen. Grund: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Scannen des USB-Speichers fehlgeschlagen. Grund: <xliff:g id="FAIL_REASON">%s</xliff:g>"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Fehler beim Lesen der SD-Karte. Grund: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"E/A-Fehler"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Zu wenig Speicherplatz (Datei ist eventuell zu groß)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Die vCard konnte aus einem unbekannten Grund nicht geparst werden."</string>
- <string name="fail_reason_not_supported" msgid="294499264620201243">"Das Format wird nicht unterstützt."</string>
+ <string name="fail_reason_not_supported" msgid="294499264620201243">"Format wird nicht unterstützt."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"vCard kann nicht importiert werden."</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"Im USB-Speicher wurde keine vCard-Datei gefunden."</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Im Speicher wurde keine vCard-Datei gefunden."</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Auf der SD-Karte wurde keine vCard-Datei gefunden."</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Metainformationen konnten nicht von den angegebenen vCards abgerufen werden."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Fehler beim Import einer oder mehrerer Dateien (%s)"</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Fehler beim Exportieren von Kontaktdaten"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Fehler beim Exportieren der Kontaktdaten."\n"Fehlerursache: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Es ist kein exportierbarer Kontakt vorhanden"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Zu viele vCard-Dateien im USB-Speicher"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Zu viele vCard-Dateien im Speicher"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Zu viele vCard-Dateien auf der SD-Karte"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Erforderlicher Dateiname ist zu lang (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Export von <xliff:g id="FILENAME">%s</xliff:g> abgeschlossen"</string>
@@ -299,8 +301,8 @@
<string name="menu_import_export" msgid="3765725645491577190">"Importieren/Exportieren"</string>
<string name="dialog_import_export" msgid="4771877268244096596">"Kontakte importieren/exportieren"</string>
<string name="menu_share" msgid="8746849630474240344">"Kontakt weitergeben"</string>
- <string name="share_via" msgid="563121028023030093">"Kontakt weiterleiten über"</string>
- <string name="share_error" msgid="4374508848981697170">"Dieser Kontakt kann nicht freigegeben werden."</string>
+ <string name="share_via" msgid="563121028023030093">"Kontakt weitergeben über"</string>
+ <string name="share_error" msgid="4374508848981697170">"Dieser Kontakt kann nicht weitergegeben werden."</string>
<string name="nameLabelsGroup" msgid="2034640839640477827">"Name"</string>
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"Alias"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"Firma/Organisation"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Phonetischer Vorname"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Phonetischer zweiter Vorname"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Phonetischer Nachname"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Phonetischer Name"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g>-Kontakt"</string>
- <string name="from_account_format" msgid="687567483928582084">"von <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Dieses Foto verwenden"</string>
<string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g>-Kontaktinformationen können auf diesem Gerät nicht bearbeitet werden."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Keine Zusatzinformationen zu diesem Kontakt"</string>
@@ -422,7 +426,7 @@
<string name="upgrade_out_of_memory" msgid="6153384328042175667">"Ihre Kontakte werden momentan aktualisiert."\n\n"Für den Aktualisierungsvorgang sind ca. <xliff:g id="SIZE_IN_MEGABYTES">%s</xliff:g> MB interner Speicher erforderlich."\n\n"Wählen Sie eine der folgenden Optionen:"</string>
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Einige Anwendungen deinstallieren"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Upgrade wiederholen"</string>
- <string name="search_results_searching" msgid="7755623475227227314">"Suche..."</string>
+ <string name="search_results_searching" msgid="7755623475227227314">"Suche läuft..."</string>
<string name="menu_display_selected" msgid="6470001164297969034">"Auswahl anzeigen"</string>
<string name="menu_display_all" msgid="8887488642609786198">"Alle anzeigen"</string>
<string name="menu_select_all" msgid="621719255150713545">"Alle auswählen"</string>
@@ -433,6 +437,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"Kein Kontakt ausgewählt"</string>
<string name="add_field" msgid="2384260056674995230">"Weiteres Feld hinzufügen"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Neue Telefonnummer"</string>
+ <string name="add_email" msgid="175079666329862215">"Neue E-Mail-Adresse"</string>
+ <string name="add_im" msgid="5158094627521120439">"Chat-Konto hinzufügen"</string>
+ <string name="add_address" msgid="418292312672970688">"Adresse hinzufügen"</string>
+ <string name="add_note" msgid="2753771325725383279">"Neue Notiz hinzufügen"</string>
+ <string name="add_website" msgid="4312391288948517344">"Website hinzufügen"</string>
+ <string name="add_event" msgid="7488781591843886426">"Ereignis hinzufügen"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Beziehung hinzufügen"</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>
<string name="description_star" msgid="2605854427360036550">"Favorit"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index a54dd00..06c45a2 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Προεπιλογή"</string>
<string name="removePhoto" msgid="4898105274130284565">"Κατάργηση εικόνας"</string>
<string name="noContacts" msgid="8579310973261953559">"Δεν υπάρχουν επαφές."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Δεν βρέθηκαν επαφές που να αντιστοιχούν."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Δεν υπάρχουν επαφές με αριθμούς τηλεφώνου."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Μόνο επαφές με τηλέφωνα"</string>
@@ -134,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"Βρέθηκαν <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Επαφές"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Αγαπ."</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Τηλέφωνο"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Αρχείο"</string>
@@ -149,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Το αρχείο καταγραφής κλήσεων είναι κενό."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Εκκαθάριση αρχείου καταγραφής κλήσεων"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Είστε βέβαιοι ότι θέλετε να γίνει εκκαθάριση του αρχείου καταγραφής κλήσεων;"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Εκκαθάριση αρχείου καταγρ. κλήσεων"</string>
<string name="imei" msgid="3045126336951684285">"Αριθμός ΙΜΕΙ"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Αυτόματος τηλεφωνητής"</string>
@@ -208,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"φωτογραφία επαφής"</string>
<string name="description_minus_button" msgid="387136707700230172">"μείον"</string>
<string name="description_plus_button" msgid="515164827856229880">"συν"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Διαθέσ. αποθηκ. χώρος USB"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Μη διαθέσιμος χώρος αποθ."</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Δεν υπάρχει κάρτα SD"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Χωρίς εντοπ. αποθ. χώρου USB"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Δεν εντοπίστηκε χώρος αποθ."</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Δεν ανιχνεύθηκε κάρτα SD"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Αναζήτηση κάρτας vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Εισαγωγή από κάρτα SIM"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Εισ. από αποθ. χώρο USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Εισαγωγή από τον χώρο αποθ."</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Εισαγωγή από κάρτα SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Εξαγ. σε αποθ. χώρο USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Εξαγωγή στον χώρο αποθ."</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Εξαγωγή σε κάρτα SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Κοινή χρήση ορατών επαφών"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Εισαγωγή ενός αρχείου VCard"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Εισαγωγή πολλαπλών αρχείων vCard"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Εισαγωγή όλων των αρχείων vCard"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Αναζήτηση δεδομένων vCard στον αποθηκευτικό χώρο USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Αναζήτηση δεδομένων vCard στον χώρο αποθήκευσης"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Αναζήτηση για δεδομένα vCard στην κάρτα SD"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Η σάρωση του αποθηκευτικού χώρου USB απέτυχε"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Η σάρωση του χώρου αποθήκευσης απέτυχε"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Η σάρωση της κάρτας SD απέτυχε"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Η σάρωση του αποθηκευτικού χώρου USB απέτυχε (Αιτία: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Η σάρωση του αποθηκευτικού χώρου απέτυχε (Αιτία: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Η σάρωση της κάρτας SD απέτυχε (Αιτία:\"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Σφάλμα I/O"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Η μνήμη είναι ανεπαρκής (το αρχείο μπορεί να είναι πολύ μεγάλο)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Η ανάλυση της κάρτας vCard απέτυχε εξαιτίας μη αναμενόμενου συμβάντος"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Η μορφή δεν υποστηρίζεται."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Αποτυχία εισαγωγής vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"Δεν βρέθηκαν αρχεία vCard στον αποθηκευτικό σας χώρο USB"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Δεν βρέθηκαν αρχεία vCard στον χώρο αποθήκευσης"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Δεν βρέθηκε αρχείο VCard στην κάρτα SD"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Η συλλογή μετα-πληροφοριών του δεδομένου αρχείου(ων) vCard απέτυχε."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Η εισαγωγή ενός ή περισσοτέρων αρχείων απέτυχε (%s)."</string>
@@ -259,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Αποτυχία εξαγωγής δεδομένων επαφής"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Αποτυχία εξαγωγής δεδομένων επαφής."\n"Αιτία αποτυχίας: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Δεν υπάρχει επαφή με δυνατότητα εξαγωγής"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Υπερβολικά μεγάλος όγκος αρχείων VCard στον αποθηκευτικό χώρο USB"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Υπερβολικά πολλά αρχεία vCard στον χώρο αποθήκευσης"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Υπερβολικά μεγάλος όγκος αρχείων VCard στην κάρτα SD"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Το απαιτούμενο όνομα αρχείου είναι υπερβολικά μεγάλο (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Η εξαγωγή ολοκληρώθηκε<xliff:g id="FILENAME">%s</xliff:g>"</string>
@@ -397,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Φωνητική μορφή ονόματος"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Φωνητική γραφή ονόματος πατρός"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Φωνητική γραφή επιθέτου"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Όνομα σε φωνητική γραφή"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> επαφή"</string>
- <string name="from_account_format" msgid="687567483928582084">"από <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Χρήση αυτής της φωτογραφίας"</string>
<string name="contact_read_only" msgid="1203216914575723978">"Τα στοιχεία επικοινωνίας της επαφής <xliff:g id="SOURCE">%1$s</xliff:g> δεν μπορούν να υποβληθούν σε επεξεργασία σε αυτήν τη συσκευή."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Δεν υπάρχουν πρόσθετες πληροφορίες για αυτήν την επαφή"</string>
@@ -430,6 +437,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"Δεν έχουν επιλεγεί επαφές."</string>
<string name="add_field" msgid="2384260056674995230">"Προσθήκη άλλου πεδίου"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Προσθ. νέου αριθ. τηλ."</string>
+ <string name="add_email" msgid="175079666329862215">"Νέα διεύθ. ηλ. ταχ."</string>
+ <string name="add_im" msgid="5158094627521120439">"Προσθήκη νέου λογ. IM"</string>
+ <string name="add_address" msgid="418292312672970688">"Προσθήκη νέας διεύθ."</string>
+ <string name="add_note" msgid="2753771325725383279">"Προσθ. νέας σημείωσης"</string>
+ <string name="add_website" msgid="4312391288948517344">"Προσθ. νέου ιστότοπου"</string>
+ <string name="add_event" msgid="7488781591843886426">"Προσθ. νέου συμβάντος"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Προσθήκη νέας σχέσης"</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>
<string name="description_star" msgid="2605854427360036550">"αγαπημένο"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index c3dccc3..ed3d6e5 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -95,6 +95,7 @@
<string name="default_ringtone" msgid="9099988849649827972">"Default"</string>
<string name="removePhoto" msgid="4898105274130284565">"Remove photo"</string>
<string name="noContacts" msgid="8579310973261953559">"No contacts."</string>
+ <string name="noGroups" msgid="8614664663561385253">"No groups."</string>
<string name="noMatchingContacts" msgid="4266283206853990471">"No matching contacts found."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"No contacts with phone numbers."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Only contacts with phones"</string>
@@ -134,6 +135,7 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> found"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Contacts"</string>
+ <string name="contactsGroupsLabel" msgid="2841971472518003524">"Groups"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favourites"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Phone"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Call log"</string>
@@ -149,6 +151,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Call log is empty."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Clear call log"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Are you sure that you want to clear the call log?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Clearing call log"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Voicemail"</string>
@@ -208,32 +211,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"contact photo"</string>
<string name="description_minus_button" msgid="387136707700230172">"minus"</string>
<string name="description_plus_button" msgid="515164827856229880">"plus"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"USB storage unavailable"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Storage unavailable"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"No SD card"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"No USB storage detected"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"No storage detected"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"No SD card detected"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Searching for vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Import from SIM card"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Import from USB storage"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Import from storage"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Import from SD card"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Export to USB storage"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Export to storage"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Export to SD card"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Share visible contacts"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Import one vCard file"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Import multiple vCard files"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Import all vCard files"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Searching for vCard data in USB storage"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Searching for vCard data in storage"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Searching for vCard data on SD card"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Scanning USB storage failed"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Scanning storage failed"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Scanning SD card failed"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Scanning USB storage failed (Reason: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Scanning USB storage failed (Reason: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Scanning SD card failed (Reason: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"I/O Error"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Memory is insufficient (the file may be too large)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Failed to parse vCard for unexpected reason"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"The format is not supported."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Failed to import vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"No vCard file found in the USB storage"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"No vCard file found in the storage"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"No vCard file found on the SD card"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Failed to collect meta information of given vCard file(s)."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"One or more files failed to be imported (%s)."</string>
@@ -259,7 +262,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Failed to export contact data"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Failed to export contact data."\n"Reason for failure: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"There is no exportable contact"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Too many vCard files in the USB storage"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Too many vCard files in the storage"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Too many vCard files on the SD card"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Required filename is too long (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Finished exporting <xliff:g id="FILENAME">%s</xliff:g>"</string>
@@ -389,25 +392,27 @@
<string name="postal_postcode" msgid="572136414136673751">"Postcode"</string>
<string name="postal_country" msgid="7638264508416368690">"Country"</string>
<string name="full_name" msgid="6602579550613988977">"Name"</string>
- <string name="name_given" msgid="1687286314106019813">"Given name"</string>
- <string name="name_family" msgid="3416695586119999058">"Family name"</string>
+ <string name="name_given" msgid="1687286314106019813">"First name"</string>
+ <string name="name_family" msgid="3416695586119999058">"Surname"</string>
<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_given" msgid="6853570431394449191">"Phonetic given name"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Phonetic middle name"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Phonetic family name"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Phonetic name"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> contact"</string>
- <string name="from_account_format" msgid="687567483928582084">"from <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Use this photo"</string>
<string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g> contact information cannot be edited on this device."</string>
<string name="no_contact_details" msgid="6754415338321837001">"No additional information for this contact"</string>
<string name="display_options_sort_list_by" msgid="6080091755852211076">"Sort list by"</string>
- <string name="display_options_sort_by_given_name" msgid="184916793466387067">"Given name"</string>
- <string name="display_options_sort_by_family_name" msgid="7857986975275712622">"Family name"</string>
+ <string name="display_options_sort_by_given_name" msgid="184916793466387067">"First name"</string>
+ <string name="display_options_sort_by_family_name" msgid="7857986975275712622">"Surname"</string>
<string name="display_options_view_names_as" msgid="18022868169627979">"View contact names as"</string>
- <string name="display_options_view_given_name_first" msgid="6968288511197363292">"Given name first"</string>
- <string name="display_options_view_family_name_first" msgid="1447288164951453714">"Family name first"</string>
+ <string name="display_options_view_given_name_first" msgid="6968288511197363292">"First name first"</string>
+ <string name="display_options_view_family_name_first" msgid="1447288164951453714">"Surname first"</string>
<string name="search_bar_hint" msgid="1012756309632856553">"Search contacts"</string>
<string name="search_for_all_contacts" msgid="6644963335787294131">"Search all contacts"</string>
<string name="take_photo" msgid="7496128293167402354">"Take photo"</string>
@@ -420,13 +425,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Uninstall some applications"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Retry upgrade"</string>
<string name="search_results_searching" msgid="7755623475227227314">"Searching..."</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"Show selected"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"Show all"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"Select all"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"Unselect all"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"No contacts selected."</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"Show selected"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"Show all"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"Select all"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"Unselect all"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"1 recipient selected"</item>
+ <item quantity="other" msgid="4608837420986126229">"<xliff:g id="COUNT">%d</xliff:g> recipients selected"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"No contacts selected."</string>
<string name="add_field" msgid="2384260056674995230">"Add another field"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Add new phone number"</string>
+ <string name="add_email" msgid="175079666329862215">"Add new email"</string>
+ <string name="add_im" msgid="5158094627521120439">"Add new IM account"</string>
+ <string name="add_address" msgid="418292312672970688">"Add new address"</string>
+ <string name="add_note" msgid="2753771325725383279">"Add new note"</string>
+ <string name="add_website" msgid="4312391288948517344">"Add new website"</string>
+ <string name="add_event" msgid="7488781591843886426">"Add new event"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Add new relationship"</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>
<string name="description_star" msgid="2605854427360036550">"favourite"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index b0d6479..d42a49f 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -41,7 +41,7 @@
<string name="menu_addStar" msgid="2908478235715404876">"Agregar a favoritos"</string>
<string name="menu_removeStar" msgid="5844227078364227030">"Eliminar de favoritos"</string>
<string name="menu_editContact" msgid="3452858480713561396">"Editar contacto"</string>
- <string name="menu_deleteContact" msgid="1916555454274101750">"Suprimir contacto"</string>
+ <string name="menu_deleteContact" msgid="1916555454274101750">"Eliminar contacto"</string>
<string name="menu_call" msgid="3992595586042260618">"Llamar al contacto"</string>
<string name="menu_sendSMS" msgid="5535886767547006515">"Enviar texto al contacto"</string>
<string name="menu_makeDefaultEmail" msgid="2599044610375789994">"Crear correo electrónico predeterminado"</string>
@@ -51,9 +51,9 @@
<string name="menu_new_contact_action_bar" msgid="8887818026717394343">"Nuevo"</string>
<string name="splitConfirmation_title" msgid="6716467920283502570">"Separar contacto"</string>
<string name="splitConfirmation" msgid="1150797297503944823">"¿Estás seguro de que deseas separar este contacto individual en varios contactos: uno para cada grupo de información de contacto que se unió a él?"</string>
- <string name="menu_joinAggregate" msgid="5027981918265667970">"Unirse"</string>
- <string name="titleJoinContactDataWith" msgid="7684875775798635354">"Unirse a contactos"</string>
- <string name="blurbJoinContactDataWith" msgid="995870557595050304">"Selecciona el contacto al que quieras unirte con <xliff:g id="NAME">%s</xliff:g>."</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"Agrupar"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"Agrupar contactos"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"Selecciona el nombre del contacto que quieras agrupar con <xliff:g id="NAME">%s</xliff:g>."</string>
<string name="showAllContactsJoinItem" msgid="2189695051430392383">"Mostrar todos los contactos"</string>
<string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"Contactos sugeridos"</string>
<string name="separatorJoinAggregateAll" msgid="7939932265026181043">"Todos los contactos"</string>
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Predeterminado"</string>
<string name="removePhoto" msgid="4898105274130284565">"Eliminar foto"</string>
<string name="noContacts" msgid="8579310973261953559">"No hay contactos."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"No se encontraron contactos coincidentes."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"No hay contactos con números de teléfono."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Sólo contactos con teléfonos"</string>
@@ -134,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g>Se encontró un"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Contactos"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoritos"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Teléfono"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Llamadas"</string>
@@ -149,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"El registro de llamadas está vacío."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Borrar registro de llamadas"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"¿Estás seguro de que deseas borrar el registro de llamadas?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Borrando el registro de llamadas"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Correo de voz"</string>
@@ -185,7 +190,7 @@
<string name="callBack" msgid="5498224409038809224">"Volver a llamar"</string>
<string name="callAgain" msgid="3197312117049874778">"Llamar nuevamente"</string>
<string name="returnCall" msgid="8171961914203617813">"Regresar llamada"</string>
- <string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g> mins <xliff:g id="SECONDS">%s</xliff:g> s"</string>
+ <string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g> min. <xliff:g id="SECONDS">%s</xliff:g> seg."</string>
<string name="favoritesFrquentSeparator" msgid="8107518433381283736">"Contactado con frecuencia"</string>
<string name="add_contact_dlg_title" msgid="2896685845822146494">"Agregar contacto"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"¿Deseas agregar \"<xliff:g id="EMAIL">%s</xliff:g>\" a los contactos?"</string>
@@ -206,34 +211,34 @@
<string name="description_delete_button" msgid="6263102114033407382">"retroceso"</string>
<string name="description_digits_edittext" msgid="8760207516497016437">"número para marcar"</string>
<string name="description_contact_photo" msgid="3387458082667894062">"foto de contacto"</string>
- <string name="description_minus_button" msgid="387136707700230172">"negativo"</string>
+ <string name="description_minus_button" msgid="387136707700230172">"menos"</string>
<string name="description_plus_button" msgid="515164827856229880">"más"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Almacenamiento USB no disponible"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"No se dispone de espacio de almacenamiento."</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"No hay tarjeta SD"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"No se detectó el almacenamiento USB"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"No se detectó almacenamiento alguno."</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"No se ha detectado ninguna tarjeta SD"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Buscando vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Importar de la tarjeta SIM"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Importar desde almacenamiento USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Importar desde el almacenamiento"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Importar de la tarjeta SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Exportar a almacenamiento USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Exportar al almacenamiento"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Exportar a la tarjeta SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Compartir contactos visibles"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Importar un archivo de vCard"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importar múltiples archivos de vCard"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Importar todos los archivos de vCard"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Buscando datos de vCard en el almacenamiento USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Buscando datos de vCard en el almacenamiento"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Buscando datos de vCard en la tarjeta SD"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"No se pudo explorar el almacenamiento USB"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"No se pudo explorar el almacenamiento."</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"No se ha podido explorar la tarjeta SD"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"No se pudo explorar el almacenamiento USB (Motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"No se pudo explorar el almacenamiento (Motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")."</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"No se ha podido explorar la tarjeta SD. (Motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Error de E/S"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Memoria insuficiente (es probable que el archivo sea muy grande)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"No se ha podido analizar vCard debido a un motivo inesperado"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"El formato no es compatible."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"No se pudo importar vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"No se encontró ningún archivo vCard en el almacenamiento USB."</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"No se encontró ningún archivo de vCard en el almacenamiento."</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"No se ha encontrado un archivo de vCard en la Tarjeta SD."</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Error al recopilar metadatos de un archivo específico de la vCard."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"No se pudieron importar uno o más archivos (%s)."</string>
@@ -246,10 +251,10 @@
<string name="reading_vcard_failed_title" msgid="2162610359561887043">"Error al leer los datos de la vCard"</string>
<string name="reading_vcard_canceled_title" msgid="1770608329958463131">"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="6367906965439777280">"La importación de <xliff:g id="FILENAME">%s</xliff:g> se canceló."</string>
+ <string name="importing_vcard_canceled_title" msgid="6367906965439777280">"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="2592424820635325951">"La solicitud para exportar la vCard se rechazó. Inténtalo nuevamente más tarde."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2592424820635325951">"Se rechazó la solicitud para importar la vCard. Inténtalo nuevamente 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>
<string name="vcard_export_request_rejected_message" msgid="8259494002258326330">"La solicitud para exportar la vCard se rechazó. Inténtalo nuevamente más tarde."</string>
<string name="vcard_unknown_filename" msgid="7171709890959915954">"contacto"</string>
@@ -259,11 +264,11 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"No se han podido exportar los datos de contacto"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"No se han podido exportar los datos de contacto."\n"Motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"No hay ningún contacto exportable"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Demasiados archivos de vCard en el almacenamiento USB"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Demasiados archivos de vCard en el almacenamiento"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Demasiados archivos de vCard en la tarjeta SD"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"El nombre de archivo requerido es demasiado largo (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Finalizó la exportación de <xliff:g id="FILENAME">%s</xliff:g>."</string>
- <string name="exporting_vcard_canceled_title" msgid="1827672399438062140">"La exportación de <xliff:g id="FILENAME">%s</xliff:g> se canceló."</string>
+ <string name="exporting_vcard_canceled_title" msgid="1827672399438062140">"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>
<string name="exporting_contact_list_message" msgid="5640326540405486055">"Exportando datos de contacto a \"<xliff:g id="FILE_NAME">%s</xliff:g>\""</string>
<string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"No se ha podido inicializar el exportador: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
@@ -389,25 +394,27 @@
<string name="postal_postcode" msgid="572136414136673751">"Código POSTAL"</string>
<string name="postal_country" msgid="7638264508416368690">"País"</string>
<string name="full_name" msgid="6602579550613988977">"Nombre"</string>
- <string name="name_given" msgid="1687286314106019813">"Nombre de pila"</string>
- <string name="name_family" msgid="3416695586119999058">"Nombre familiar"</string>
+ <string name="name_given" msgid="1687286314106019813">"Nombre"</string>
+ <string name="name_family" msgid="3416695586119999058">"Apellido"</string>
<string name="name_prefix" msgid="59756378548779822">"Prefijo del nombre"</string>
<string name="name_middle" msgid="8467433655992690326">"Segundo nombre"</string>
<string name="name_suffix" msgid="3855278445375651441">"Sufijo del nombre"</string>
- <string name="name_phonetic_given" msgid="6853570431394449191">"Nombre de pila fonético"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"Nombre fonético"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Segundo nombre fonético"</string>
- <string name="name_phonetic_family" msgid="462095502140180305">"Nombre familiar fonético"</string>
- <string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> contacto"</string>
- <string name="from_account_format" msgid="687567483928582084">"de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"Apellido fonético"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Nombre fonético"</string>
+ <string name="account_type_format" msgid="718948015590343010">"Contacto de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Usar esta foto"</string>
<string name="contact_read_only" msgid="1203216914575723978">"La información de <xliff:g id="SOURCE">%1$s</xliff:g> contactos no se puede editar en este dispositivo."</string>
<string name="no_contact_details" msgid="6754415338321837001">"No hay información adicional para este contacto."</string>
<string name="display_options_sort_list_by" msgid="6080091755852211076">"Ordenar listas por"</string>
- <string name="display_options_sort_by_given_name" msgid="184916793466387067">"Nombre de pila"</string>
- <string name="display_options_sort_by_family_name" msgid="7857986975275712622">"Nombre familiar"</string>
+ <string name="display_options_sort_by_given_name" msgid="184916793466387067">"Nombre"</string>
+ <string name="display_options_sort_by_family_name" msgid="7857986975275712622">"Apellido"</string>
<string name="display_options_view_names_as" msgid="18022868169627979">"Ver nombres de contacto como"</string>
- <string name="display_options_view_given_name_first" msgid="6968288511197363292">"Nombre de pila en primer lugar"</string>
- <string name="display_options_view_family_name_first" msgid="1447288164951453714">"Nombre familiar en primer lugar"</string>
+ <string name="display_options_view_given_name_first" msgid="6968288511197363292">"Nombre primero"</string>
+ <string name="display_options_view_family_name_first" msgid="1447288164951453714">"Apellido primero"</string>
<string name="search_bar_hint" msgid="1012756309632856553">"Buscar contactos"</string>
<string name="search_for_all_contacts" msgid="6644963335787294131">"Buscar todos los contactos"</string>
<string name="take_photo" msgid="7496128293167402354">"Tomar foto"</string>
@@ -430,6 +437,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"No hay contactos seleccionados."</string>
<string name="add_field" msgid="2384260056674995230">"Agregar otro campo"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Agregar nuevo número de teléfono"</string>
+ <string name="add_email" msgid="175079666329862215">"Agregar nuevo correo"</string>
+ <string name="add_im" msgid="5158094627521120439">"Agregar nueva cuenta de MI"</string>
+ <string name="add_address" msgid="418292312672970688">"Agregar nueva dirección"</string>
+ <string name="add_note" msgid="2753771325725383279">"Agregar nueva nota"</string>
+ <string name="add_website" msgid="4312391288948517344">"Agregar nuevo sitio web"</string>
+ <string name="add_event" msgid="7488781591843886426">"Agregar nuevo evento"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Agregar nueva relación"</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>
<string name="description_star" msgid="2605854427360036550">"favorito"</string>
@@ -439,8 +454,8 @@
<item quantity="other" msgid="425683718017380845">"combinado a partir de fuentes <xliff:g id="COUNT">%0$d</xliff:g>"</item>
</plurals>
<string name="local_invisible_directory" msgid="6046691709127661065">"Otro"</string>
- <string name="aggregation_suggestion_join_dialog_title" msgid="5276699501316246253">"Unirse a contactos"</string>
- <string name="aggregation_suggestion_join_dialog_message" msgid="3842757977671434836">"¿Unir contacto actual a contacto seleccionado?"</string>
+ <string name="aggregation_suggestion_join_dialog_title" msgid="5276699501316246253">"Agrupar contactos"</string>
+ <string name="aggregation_suggestion_join_dialog_message" msgid="3842757977671434836">"¿Deseas agrupar el contacto actual con el contacto seleccionado?"</string>
<string name="aggregation_suggestion_edit_dialog_title" msgid="1064042382692091314">"Modificar contactos seleccionados"</string>
<string name="aggregation_suggestion_edit_dialog_message" msgid="6549585283910518095">"¿Optar por modificar contacto seleccionado? Se copiará la información que ingresaste hasta ahora."</string>
<string name="menu_copyContact" msgid="4401683725471696686">"Copiar a mis contactos"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index ff2b248..9bc3152 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -86,7 +86,7 @@
<item msgid="8287841928119937597">"Organización"</item>
<item msgid="7196592230748086755">"Nota"</item>
</string-array>
- <string name="photoPickerNotFoundText" product="tablet" msgid="6247290728908599701">"No hay ninguna imagen disponible en la tableta."</string>
+ <string name="photoPickerNotFoundText" product="tablet" msgid="6247290728908599701">"No hay ninguna imagen disponible en el tablet."</string>
<string name="photoPickerNotFoundText" product="default" msgid="431331662154342581">"No hay ninguna imagen disponible en el teléfono."</string>
<string name="attach_photo_dialog_title" msgid="5599827035558557169">"Foto de contacto"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"Nombre de etiqueta personalizada"</string>
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Predeterminado"</string>
<string name="removePhoto" msgid="4898105274130284565">"Eliminar foto"</string>
<string name="noContacts" msgid="8579310973261953559">"No hay ningún contacto."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"No se ha encontrado ningún contacto coincidente."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"No hay ningún contacto con número de teléfono."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Solo contactos con teléfono"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"Un (1) contacto con número de teléfono"</item>
<item quantity="other" msgid="3299954047880968205">"<xliff:g id="COUNT">%d</xliff:g> contactos con números de teléfono"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"No hay ningún contacto visible con número de teléfono."</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Ningún contacto con número de teléfono"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"Un (1) contacto"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> contactos"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"No hay contactos visibles."</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Ningún contacto"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Ningún contacto visible"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Ningún contacto destacado"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Ningún contacto en <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"1 encontrado"</item>
<item quantity="other" msgid="3852668542926965042">"<xliff:g id="COUNT">%d</xliff:g> encontrados"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> encontrados"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Contactos"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoritos"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Teléfono"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Llamadas"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"El registro de llamadas está vacío."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Borrar registro de llamadas"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"¿Estás seguro de que quieres borrar el registro de llamadas?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Borrando registro de llamadas"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Buzón de voz"</string>
@@ -164,13 +166,13 @@
<string name="simContacts_title" msgid="27341688347689769">"Contactos de tarjeta SIM"</string>
<string name="noContactsHelpTextWithSyncForCreateShortcut" msgid="801504710275614594">"No tienes ningún contacto que mostrar. (Si acabas de añadir una cuenta, es posible que la sincronización de contactos tarde algunos minutos)."</string>
<string name="noContactsHelpTextForCreateShortcut" msgid="3081286388667108335">"No tienes ningún contacto que mostrar."</string>
- <string name="noContactsHelpText" product="tablet" msgid="6450346791169710787">"No tienes contactos."\n\n"Para añadir uno, pulsa la tecla de menú"<font fgcolor="#ffffffff"><b></b></font>" y toca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para añadir o configurar una cuenta con los contactos que puedes sincronizar con la tableta,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear un nuevo contacto, o"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/exportar"</b></font>" para importar contactos desde la tarjeta SIM o SD"\n</li>"."</string>
+ <string name="noContactsHelpText" product="tablet" msgid="6450346791169710787">"No tienes contactos."\n\n"Para añadir uno, pulsa la tecla de menú"<font fgcolor="#ffffffff"><b></b></font>" y toca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para añadir o configurar una cuenta con los contactos que puedes sincronizar con el tablet,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear un nuevo contacto, o"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/exportar"</b></font>" para importar contactos desde la tarjeta SIM o SD"\n</li>"."</string>
<string name="noContactsHelpText" product="default" msgid="7633826236417884130">"No tienes contactos."\n\n"Para añadir uno, pulsa la tecla de menú"<font fgcolor="#ffffffff"><b></b></font>" y toca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para añadir o configurar una cuenta con los contactos que puedes sincronizar,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear un nuevo contacto,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/exportar"</b></font>" para importar contactos desde la tarjeta SIM o SD"\n</li>"."</string>
- <string name="noContactsHelpTextWithSync" product="tablet" msgid="2364665535969139880">"No tienes contactos. Si acabas de añadir una cuenta, la sincronización puede tardar."\n\n"Para añadir contactos, pulsa la tecla de menú"<font fgcolor="#ffffffff"><b></b></font>" y toca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para añadir o configurar una cuenta con contactos que puedes sincronizar con la tableta,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Opciones de visualización"</b></font>" para modificar los contactos visibles,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear un nuevo contacto, o"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/exportar"</b></font>" para importar contactos desde la tarjeta SIM o SD"\n</li>"."</string>
+ <string name="noContactsHelpTextWithSync" product="tablet" msgid="2364665535969139880">"No tienes contactos. Si acabas de añadir una cuenta, la sincronización puede tardar."\n\n"Para añadir contactos, pulsa la tecla de menú"<font fgcolor="#ffffffff"><b></b></font>" y toca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para añadir o configurar una cuenta con contactos que puedes sincronizar con el tablet,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Opciones de visualización"</b></font>" para modificar los contactos visibles,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear un nuevo contacto, o"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/exportar"</b></font>" para importar contactos desde la tarjeta SIM o SD"\n</li>"."</string>
<string name="noContactsHelpTextWithSync" product="default" msgid="3017521127042216243">"No tienes contactos. Si acabas de añadir una cuenta, la sincronización puede tardar."\n\n"Para añadir contactos, pulsa la tecla de menú"<font fgcolor="#ffffffff"><b></b></font>" y toca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para añadir o configurar una cuenta con contactos que puedes sincronizar,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Opciones de visualización"</b></font>" para modificar los contactos visibles,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear un nuevo contacto,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/exportar"</b></font>" para importar contactos desde la tarjeta SIM o SD"\n</li>"."</string>
- <string name="noContactsNoSimHelpText" product="tablet" msgid="6031363021287849874">"No tienes contactos."\n\n"Para añadir uno, pulsa la tecla de menú"<font fgcolor="#ffffffff"><b></b></font>" y toca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para añadir o configurar una cuenta con los contactos que puedes sincronizar con la tableta,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear un nuevo contacto, o"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/exportar"</b></font>" para importar contactos desde la tarjeta SD"\n</li>"."</string>
+ <string name="noContactsNoSimHelpText" product="tablet" msgid="6031363021287849874">"No tienes contactos."\n\n"Para añadir uno, pulsa la tecla de menú"<font fgcolor="#ffffffff"><b></b></font>" y toca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para añadir o configurar una cuenta con los contactos que puedes sincronizar con el tablet,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear un nuevo contacto, o"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/exportar"</b></font>" para importar contactos desde la tarjeta SD"\n</li>"."</string>
<string name="noContactsNoSimHelpText" product="default" msgid="467658807711582876">"No tienes contactos."\n\n"Para añadir uno, pulsa la tecla de menú"<font fgcolor="#ffffffff"><b></b></font>" y toca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para añadir o configurar una cuenta con los contactos que puedes sincronizar,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear un nuevo contacto,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/exportar"</b></font>" para importar contactos desde la tarjeta SD"\n</li>"."</string>
- <string name="noContactsNoSimHelpTextWithSync" product="tablet" msgid="6222739731808897565">"No tienes contactos. Si acabas de añadir una cuenta, la sincronización de contactos puede tardar unos minutos."\n\n"Para añadir contactos, pulsa la tecla de menú"<font fgcolor="#ffffffff"><b></b></font>" y toca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para añadir o configurar una cuenta con contactos que puedes sincronizar con la tableta,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Opciones de visualización"</b></font>" para modificar los contactos visibles,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear un nuevo contacto, o"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/exportar"</b></font>" para importar contactos desde la tarjeta SD"\n</li>"."</string>
+ <string name="noContactsNoSimHelpTextWithSync" product="tablet" msgid="6222739731808897565">"No tienes contactos. Si acabas de añadir una cuenta, la sincronización de contactos puede tardar unos minutos."\n\n"Para añadir contactos, pulsa la tecla de menú"<font fgcolor="#ffffffff"><b></b></font>" y toca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para añadir o configurar una cuenta con contactos que puedes sincronizar con el tablet,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Opciones de visualización"</b></font>" para modificar los contactos visibles,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear un nuevo contacto, o"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/exportar"</b></font>" para importar contactos desde la tarjeta SD"\n</li>"."</string>
<string name="noContactsNoSimHelpTextWithSync" product="default" msgid="9040060730467973050">"No tienes contactos. Si acabas de añadir una cuenta, la sincronización puede tardar."\n\n"Para añadir contactos, pulsa la tecla de menú"<font fgcolor="#ffffffff"><b></b></font>" y toca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para añadir o configurar una cuenta con contactos que puedes sincronizar,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Opciones de visualización"</b></font>" para modificar los contactos visibles,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear un nuevo contacto,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/exportar"</b></font>" para importar contactos desde la tarjeta SD"\n</li>"."</string>
<string name="noFavoritesHelpText" msgid="3744655776704833277">"No tienes favoritos."\n\n"Para añadir un contacto a tu lista de favoritos, sigue estos pasos:"\n\n" "<li>"Toca en la pestaña "<b>"Contactos"</b>"."\n</li>" "\n<li>"Selecciona el contacto que quieras añadir a tus favoritos."\n</li>" "\n<li>"Toca la estrella situada junto al nombre del contacto."\n</li></string>
<string name="liveFolder_all_label" msgid="5961411940473276616">"Todos los contactos"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"foto de contacto"</string>
<string name="description_minus_button" msgid="387136707700230172">"menos"</string>
<string name="description_plus_button" msgid="515164827856229880">"más"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"USB no disponible"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Almacenamiento no disponible"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Falta la tarjeta SD."</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"USB no detectado"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Sin almacenamiento detectado"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"No se ha detectado ninguna tarjeta SD."</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Buscando vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Importar contactos desde la tarjeta SIM"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Importar de USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Importar de almacenamiento"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Importar contactos desde la tarjeta SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Exportar a USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Exportar a almacenamiento"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Exportar contactos a la tarjeta SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Compartir contactos visibles"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Importar un archivo de vCard"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importar varios archivos de vCard"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Importar todos los archivos de vCard"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Buscando datos de vCard en USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Buscando datos de vCard en almacenamiento"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Buscando datos de vCard en la tarjeta SD"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Error al analizar USB"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Error al analizar almacenamiento"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Error al buscar en la tarjeta SD"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Error al analizar USB (Motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Error al analizar almacenamiento (Motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Error al buscar en la tarjeta SD (motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Error de E/S"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Memoria insuficiente (el archivo puede ser demasiado grande)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"No se ha podido analizar el archivo de vCard debido a un error inesperado."</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"No se admite este formato."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Se ha producido un error al importar vCard."</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"No se ha encontrado el archivo de vCard en el almacenamiento USB."</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"No se han encontrado archivos de vCard en el almacenamiento."</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"No se ha encontrado ningún archivo de vCard en la tarjeta SD."</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Error al recopilar metainformación de los archivos vCard"</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"No ha sido posible importar uno o varios archivos (%s)."</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Error al exportar los datos del contacto"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Se ha producido un error al exportar los datos del contacto."\n"Motivo del error: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"No hay contactos que exportar."</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Hay demasiados archivos de vCard en el almacenamiento USB."</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Hay demasiados archivos de vCard en el almacenamiento."</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Hay demasiados archivos de vCard en la tarjeta SD."</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"El nombre de archivo necesario es demasiado largo (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Exportación de <xliff:g id="FILENAME">%s</xliff:g> finalizada"</string>
@@ -272,7 +274,7 @@
<string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"No se ha podido inicializar el exportador: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"Se ha producido un error durante la exportación: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
<string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"Error al obtener información de la base de datos"</string>
- <string name="composer_has_no_exportable_contact" product="tablet" msgid="5161491059051198932">"No hay contactos que exportar. Si ya tienes contactos en la tableta, es posible que algunos proveedores de datos no permitan que se exporten todos los contactos a otros dispositivos."</string>
+ <string name="composer_has_no_exportable_contact" product="tablet" msgid="5161491059051198932">"No hay contactos que exportar. Si ya tienes contactos en el tablet, es posible que algunos proveedores de datos no permitan que se exporten todos los contactos a otros dispositivos."</string>
<string name="composer_has_no_exportable_contact" product="default" msgid="322344221706924358">"No hay contactos que exportar. Si ya tienes contactos en tu teléfono, es posible que algunos proveedores de datos no permitan que se exporten todos los contactos a otros dispositivos."</string>
<string name="composer_not_initialized" msgid="8041534450748388843">"El redactor de vCard no se ha inicializado correctamente."</string>
<string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"No se ha podido abrir el archivo \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
@@ -320,7 +322,7 @@
<string name="display_ungrouped" msgid="4602580795576261158">"Todos los demás contactos"</string>
<string name="display_all_contacts" msgid="6846131371214707956">"Todos los contactos"</string>
<string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"Si eliminas \"<xliff:g id="GROUP">%s</xliff:g>\" de la sincronización, también se eliminarán todos los contactos no agrupados."</string>
- <string name="account_phone" product="tablet" msgid="7946049152658522054">"Sólo en la tableta (sin sincronizar)"</string>
+ <string name="account_phone" product="tablet" msgid="7946049152658522054">"Solo en el tablet (sin sincronizar)"</string>
<string name="account_phone" product="default" msgid="3682950835276226870">"Solo en el teléfono, no sincronizado"</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>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Nombre fonético"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Segundo nombre fonético"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Apellido fonético"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Transcripción fonética del nombre"</string>
<string name="account_type_format" msgid="718948015590343010">"Contacto de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
- <string name="from_account_format" msgid="687567483928582084">"de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Utilizar esta foto"</string>
<string name="contact_read_only" msgid="1203216914575723978">"No se puede editar la información del contacto de <xliff:g id="SOURCE">%1$s</xliff:g> en este dispositivo."</string>
<string name="no_contact_details" msgid="6754415338321837001">"No hay información adicional para este contacto."</string>
@@ -433,6 +437,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"No hay ningún contacto seleccionado."</string>
<string name="add_field" msgid="2384260056674995230">"Añadir otro campo"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Añadir nuevo teléfono"</string>
+ <string name="add_email" msgid="175079666329862215">"Añadir nuevo correo"</string>
+ <string name="add_im" msgid="5158094627521120439">"Añadir nueva cuenta MI"</string>
+ <string name="add_address" msgid="418292312672970688">"Añadir nueva dirección"</string>
+ <string name="add_note" msgid="2753771325725383279">"Añadir nueva nota"</string>
+ <string name="add_website" msgid="4312391288948517344">"Añadir nuevo sitio web"</string>
+ <string name="add_event" msgid="7488781591843886426">"Añadir nuevo evento"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Añadir nueva relación"</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>
<string name="description_star" msgid="2605854427360036550">"favoritos"</string>
@@ -446,7 +458,7 @@
<string name="aggregation_suggestion_join_dialog_message" msgid="3842757977671434836">"¿Deseas agrupar el contacto actual con el contacto seleccionado?"</string>
<string name="aggregation_suggestion_edit_dialog_title" msgid="1064042382692091314">"Editar contactos seleccionados"</string>
<string name="aggregation_suggestion_edit_dialog_message" msgid="6549585283910518095">"¿Deseas editar el contacto seleccionado? Se copiará la información que hayas introducido hasta el momento."</string>
- <string name="menu_copyContact" msgid="4401683725471696686">"Copiar a mis contactos"</string>
+ <string name="menu_copyContact" msgid="4401683725471696686">"Copiar en mis contactos"</string>
<string name="contact_directory_description" msgid="683398073603909119">"Directorio <xliff:g id="TYPE">%1$s</xliff:g>"</string>
<string name="search_label" msgid="6789295859496641042">"Buscando todos los contactos"</string>
<string name="directory_search_label" msgid="1887759056597975053">"Directorio"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index e7e73d5..f6ac2e2 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"پیش فرض"</string>
<string name="removePhoto" msgid="4898105274130284565">"حذف عکس"</string>
<string name="noContacts" msgid="8579310973261953559">"مخاطبی موجود نیست."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"مخاطب منطبقی یافت نشد."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"مخاطبی با شماره تلفن موجود نیست."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"فقط مخاطبین دارای شماره تلفن"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"1 مخاطب با شماره تلفن"</item>
<item quantity="other" msgid="3299954047880968205">"<xliff:g id="COUNT">%d</xliff:g> مخاطب دارای شماره تلفن"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"مخاطب قابل رؤیتی با شماره تلفن موجود نیست"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"مخاطبی با شماره تلفن موجود نیست"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 مخاطب"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> مخاطب"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"مخاطب قابل رؤیتی موجود نیست"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"مخاطبی موجود نیست"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"مخاطب قابل رؤیتی موجود نیست"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"هیچ مخاطب ستاره داری موجود نیست"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"هیچ مخاطبی در <xliff:g id="NAME">%s</xliff:g> موجود نیست"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"1 مورد پیدا شد"</item>
<item quantity="other" msgid="3852668542926965042">"<xliff:g id="COUNT">%d</xliff:g> یافت شد"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> یافت شد"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"مخاطبین"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"موارد دلخواه"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"تلفن"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"گزارش تماس"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"گزارش تماس خالی است."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"پاک کردن گزارش تماس"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"آیا مطمئن هستید که می خواهید گزارش تماس را پاک کنید؟"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"پاک کردن گزارش تماس"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"پست صوتی"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"عکس مخاطب"</string>
<string name="description_minus_button" msgid="387136707700230172">"منها"</string>
<string name="description_plus_button" msgid="515164827856229880">"به اضافه"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"حافظه USB در دسترس نیست"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"حافظه در دسترس نیست"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"کارت SD موجود نیست"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"حافظه USB یافت نشد"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"حافظه ای شناسایی نشد"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"هیچ کارت SD شناسایی نشد"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"جستجوی کارت ویزیت"</string>
<string name="import_from_sim" msgid="3859272228033941659">"وارد کردن از سیم کارت"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"وارد کردن از حافظه USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"وارد کردن از حافظه"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"وارد کردن از کارت SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"صادر کردن به حافظه USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"صادر کردن به حافظه"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"صدور به کارت SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"اشتراک گذاری مخاطبین قابل مشاهده"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"وارد کردن یک فایل کارت ویزیت"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"وارد کردن چند فایل کارت ویزیت"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"وارد کردن همه فایل های کارت ویزیت"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"جستجوی داده کارت ویزیت در حافظه USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"جستجوی داده کارت ویزیت در حافظه"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"جستجوی داده های کارت ویزیت در کارت SD"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"اسکن حافظه USB ناموفق بود"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"اسکن حافظه انجام نشد"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"اسکن کارت SD انجام نشد"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"اسکن حافظه USB ناموفق بود (دلیل: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"اسکن حافظه ناموفق بود (دلیل: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"اسکن کارت SD انجام نشد (دلیل: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"خطای ورودی/خروجی"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"حافظه کافی نیست (ممکن است فایل بسیار بزرگ باشد)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"تجزیه کارت ویزیت به دلیل پیش بینی نشده انجام نشد"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"قالب پشتیبانی نمی شود."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"vCard وارد نشد"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"فایل کارت ویزیتی در دستگاه ذخیره USB یافت نشد"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"فایل کارت ویزیت در حافظه یافت نشد"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"فایل کارت ویزیتی در کارت SD یافت نشد"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"جمع آوری فوق اطلاعات فایل(های) کارت ویزیت موجود ناموفق بود."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"یک یا چند فایل وارد نشدند (%s)."</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"صدور اطلاعات مخاطب انجام نشد"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"صدور اطلاعات مخاطب انجام نشد."\n"دلیل خطا: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"هیچ مخاطب قابل صدوری موجود نیست"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"تعداد فایل های کارت ویزیت در حافظه USB بسیار زیاد است"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"تعداد فایل های کارت ویزیت در حافظه بسیار زیاد است"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"فایل های کارت ویزیت بسیار زیادی در کارت SD وجود دارد"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"نام فایل ضروری خیلی طولانی است (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"صادر کردن <xliff:g id="FILENAME">%s</xliff:g> پایان یافت"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"تلفظ نام"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"تلفظ نام میانی"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"تلفظ آوایی نام خانوادگی"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"تلفظ نام"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> مخاطب"</string>
- <string name="from_account_format" msgid="687567483928582084">"از <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"استفاده از این عکس"</string>
<string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g> اطلاعات مخاطب در این دستگاه قابل ویرایش نمی باشد."</string>
<string name="no_contact_details" msgid="6754415338321837001">"اطلاعات دیگری برای این مخاطب موجود نیست"</string>
@@ -423,13 +427,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"حذف نصب برخی از برنامه های کاربردی"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"امتحان مجدد برای ارتقا"</string>
<string name="search_results_searching" msgid="7755623475227227314">"در حال جستجو..."</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"نمایش موارد انتخاب شده"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"نمایش همه"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"انتخاب همه"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"لغو انتخاب همه موارد"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"مخاطبی انتخاب نشده است."</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"نمایش موارد انتخاب شده"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"نمایش همه"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"انتخاب همه"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"لغو انتخاب همه موارد"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"1 گیرنده انتخاب شد"</item>
+ <item quantity="other" msgid="4608837420986126229">"<xliff:g id="COUNT">%d</xliff:g> گیرنده انتخاب شد"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"مخاطبی انتخاب نشده است."</string>
<string name="add_field" msgid="2384260056674995230">"افزودن یک قسمت دیگر"</string>
+ <string name="add_phone" msgid="4421904942555210013">"افزودن شماره تلفن جدید"</string>
+ <string name="add_email" msgid="175079666329862215">"افزودن ایمیل جدید"</string>
+ <string name="add_im" msgid="5158094627521120439">"افزودن حساب IM جدید"</string>
+ <string name="add_address" msgid="418292312672970688">"افزودن آدرس جدید"</string>
+ <string name="add_note" msgid="2753771325725383279">"افزودن یادداشت جدید"</string>
+ <string name="add_website" msgid="4312391288948517344">"افزودن وب سایت جدید"</string>
+ <string name="add_event" msgid="7488781591843886426">"افزودن رویداد جدید"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"افزودن رابطه جدید"</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>
<string name="description_star" msgid="2605854427360036550">"مورد دلخواه"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index e6c4509..92944c1 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Oletus"</string>
<string name="removePhoto" msgid="4898105274130284565">"Poista kuva"</string>
<string name="noContacts" msgid="8579310973261953559">"Ei yhteystietoja."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Hakua vastaavia yhteystietoja ei löydy."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Ei yhteystietoja, joissa on puhelinnumero."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Vain yhteystiedot, joissa on puhelinnumero"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"1 yhteystieto, jossa puhelinnumero"</item>
<item quantity="other" msgid="3299954047880968205">"<xliff:g id="COUNT">%d</xliff:g> yhteystietoa, joissa puhelinnumero"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Ei näkyviä yhteystietoja, joissa on puhelinnumero"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Ei yhteystietoja, joissa on puhelinnumero"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 yhteystieto"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> yhteystietoa"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Ei näkyviä yhteystietoja"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Ei yhteystietoja"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Ei näkyviä yhteystietoja"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Ei tähdellisiä yhteystietoja"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Ei yhteystietoja ryhmässä <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"Löytyi 1"</item>
<item quantity="other" msgid="3852668542926965042">"Löytyi <xliff:g id="COUNT">%d</xliff:g>"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"Löytyi <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Yhteystiedot"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Suosikit"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Puhelin"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Puheluloki"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Puheluloki on tyhjä."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Tyhjennä puheluloki"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Haluatko varmasti tyhjentää puhelulokin?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Tyhjennetään puhelulokia"</string>
<string name="imei" msgid="3045126336951684285">"IMEI-koodi"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Vastaaja"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"yhteystiedon valokuva"</string>
<string name="description_minus_button" msgid="387136707700230172">"miinus"</string>
<string name="description_plus_button" msgid="515164827856229880">"plus"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"USB-tila ei käytettävissä"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Tallennustila ei käytettävissä"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Ei SD-korttia"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Ei USB-tallennustilaa"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Tallennustilaa ei havaittu"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"SD-korttia ei havaittu"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Etsitään vCardia"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Tuo SIM-kortilta"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Tuo USB-tilasta"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Tuo tallennustilasta"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Tuo SD-kortilta"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Vie USB-tilaan"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Vie tallennustilaan"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Vie SD-kortille"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Jaa näkyvät yhteystiedot"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Tuo yksi vCard-tiedosto"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Tuo useita vCard-tiedostoja"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Tuo kaikki vCard-tiedostot"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Haetaan vCard-tietoja USB-tallennustilasta"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Etsitään vCard-tietoja tallennustilasta"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Etsitään vCard-tietoja SD-kortilta"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"USB-tallennustilan lukeminen epäonnistui"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Tallennustilan lukeminen epäonnistui"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"SD-kortin lukeminen epäonnistui"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"USB-tallennustilan lukeminen epäonnistui (syy: <xliff:g id="FAIL_REASON">%s</xliff:g>)"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Tallennustilan lukeminen epäonnistui (Syy: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"SD-kortin lukeminen epäonnistui (Syy: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"I/O-virhe"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Muisti ei riitä (tiedosto voi olla liian suuri)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"vCardin jäsennys epäonnistui tuntemattomasta syystä"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Muotoa ei tueta."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"vCard-tietojen tuonti epäonnistui"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"USB-tallennustilasta ei löydy vCard-tiedostoa"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Tallennustilasta ei löydy vCard-tiedostoja"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"SD-kortilta ei löydy vCard-tiedostoa"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Annettujen vCard-tiedostojen sisällönkuvaustietojen noutaminen epäonnistui."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Ainakin yhden tiedoston tuominen epäonnistui (%s)."</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Yhteystietojen vieminen epäonnistui"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Yhteystietojen vieminen epäonnistui."\n"Virheen syy: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Ei vietäviä yhteystietoja"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Liikaa vCard-tiedostoja USB-tallennustilassa"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Tallennustilassa on liian monta vCard-tiedostoa"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"SD-kortilla on liian monta vCard-tiedostoa"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Tarvittava tiedostonimi on liian pitkä (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Kohteen <xliff:g id="FILENAME">%s</xliff:g> vienti valmis"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Etunimen ääntämistapa"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Toisen nimen ääntämistapa"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Sukunimen ääntämistapa"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Nimen ääntämistapa"</string>
<string name="account_type_format" msgid="718948015590343010">"Tilin <xliff:g id="SOURCE">%1$s</xliff:g> yhteystieto"</string>
- <string name="from_account_format" msgid="687567483928582084">"tilistä <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Käytä valokuvaa"</string>
<string name="contact_read_only" msgid="1203216914575723978">"Tilin <xliff:g id="SOURCE">%1$s</xliff:g> yhteystietoja ei voi muokata tällä laitteella."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Tässä yhteystiedossa ei ole muita tietoja"</string>
@@ -423,13 +427,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Poista sovelluksia"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Yritä päivitystä uudelleen"</string>
<string name="search_results_searching" msgid="7755623475227227314">"Haetaan…"</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"Näytä valitut"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"Näytä kaikki"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"Valitse kaikki"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"Poista kaikki valinnat"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"Ei valittuja yhteystietoja."</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"Näytä valitut"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"Näytä kaikki"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"Valitse kaikki"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"Poista kaikki valinnat"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"1 vastaanottaja valittu"</item>
+ <item quantity="other" msgid="4608837420986126229">"<xliff:g id="COUNT">%d</xliff:g> vastaanottajaa valittu"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"Ei valittuja yhteystietoja."</string>
<string name="add_field" msgid="2384260056674995230">"Lisää toinen kenttä"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Lisää uusi puh.numero"</string>
+ <string name="add_email" msgid="175079666329862215">"Lisää uusi sähköposti"</string>
+ <string name="add_im" msgid="5158094627521120439">"Lisää uusi pikav.tili"</string>
+ <string name="add_address" msgid="418292312672970688">"Lisää uusi osoite"</string>
+ <string name="add_note" msgid="2753771325725383279">"Lisää uusi huomautus"</string>
+ <string name="add_website" msgid="4312391288948517344">"Lisää uusi sivusto"</string>
+ <string name="add_event" msgid="7488781591843886426">"Lisää uusi tapahtuma"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Lisää uusi suhde"</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>
<string name="description_star" msgid="2605854427360036550">"lisää suosikkeihin"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index ad48ca6..5e89379 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -71,7 +71,7 @@
<string name="editContact_title_insert" msgid="9125600232291405757">"Nouveau contact"</string>
<string name="label_phonetic_name" msgid="2288082649573927286">"Prononciation phonétique"</string>
<string name="label_notes" msgid="8337354953278341042">"Notes"</string>
- <string name="label_sip_address" msgid="124073911714324974">"Appel VoIP"</string>
+ <string name="label_sip_address" msgid="124073911714324974">"Appel Internet"</string>
<string name="label_ringtone" msgid="8833166825330686244">"Sonnerie"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"Nom phonétique"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Entreprise"</string>
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Par défaut"</string>
<string name="removePhoto" msgid="4898105274130284565">"Supprimer la photo"</string>
<string name="noContacts" msgid="8579310973261953559">"Aucun contact."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Aucun contact correspondant n\'a été trouvé."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Aucun contact disposant d\'un numéro téléphone."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Contacts avec un n° de tél."</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"1 contact avec numéro de téléphone"</item>
<item quantity="other" msgid="3299954047880968205">"<xliff:g id="COUNT">%d</xliff:g> contacts avec des n° de téléphone"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Aucun contact visible avec numéro de téléphone"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Aucun contact disposant d\'un numéro de téléphone"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 contact"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> contacts"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Aucun contact visible"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Aucun contact"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Aucun contact visible"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Aucun contact favori"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Aucun contact dans <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"1 contact trouvé"</item>
<item quantity="other" msgid="3852668542926965042">"<xliff:g id="COUNT">%d</xliff:g> contact(s) trouvé(s)"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> contact(s) trouvé(s)"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Contacts"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoris"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Tél."</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Appels"</string>
@@ -152,11 +153,12 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Aucun appel."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Effacer le journal d\'appels"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Voulez-vous vraiment effacer le journal d\'appels ?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Suppression du journal d\'appels"</string>
<string name="imei" msgid="3045126336951684285">"Code IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Messagerie vocale"</string>
<string name="unknown" msgid="740067747858270469">"Inconnu"</string>
- <string name="private_num" msgid="6374339738119166953">"Numéro privée"</string>
+ <string name="private_num" msgid="6374339738119166953">"Numéro privé"</string>
<string name="payphone" msgid="4864313342828942922">"Cabine téléphonique"</string>
<string name="dialerKeyboardHintText" msgid="5401660096579787344">"Utilisez le clavier pour composer le numéro"</string>
<string name="dialerDialpadHintText" msgid="5824490365898349041">"Composer"</string>
@@ -164,12 +166,12 @@
<string name="simContacts_title" msgid="27341688347689769">"Contacts de carte SIM"</string>
<string name="noContactsHelpTextWithSyncForCreateShortcut" msgid="801504710275614594">"Vous n\'avez aucun contact à afficher. Si vous venez d\'ajouter un compte, la synchronisation des contacts peut prendre quelques minutes."</string>
<string name="noContactsHelpTextForCreateShortcut" msgid="3081286388667108335">"Vous n\'avez aucun contact à afficher."</string>
- <!-- syntax error in translation for noContactsHelpText (6450346791169710787) org.xmlpull.v1.XmlPullParserException: expected: /b read: font (position:END_TAG </font>@1:560 in java.io.StringReader@3ced0338) -->
- <!-- syntax error in translation for noContactsHelpText (7633826236417884130) org.xmlpull.v1.XmlPullParserException: expected: /b read: font (position:END_TAG </font>@1:567 in java.io.StringReader@6c6e70c7) -->
+ <!-- syntax error in translation for noContactsHelpText (6450346791169710787) org.xmlpull.v1.XmlPullParserException: expected: /b read: font (position:END_TAG </font>@1:560 in java.io.StringReader@17dfafd1) -->
+ <!-- syntax error in translation for noContactsHelpText (7633826236417884130) org.xmlpull.v1.XmlPullParserException: expected: /b read: font (position:END_TAG </font>@1:567 in java.io.StringReader@5e8fce95) -->
<string name="noContactsHelpTextWithSync" product="tablet" msgid="2364665535969139880">"Vous n\'avez aucun contact à afficher (si vous venez d\'ajouter un compte, la synchronisation des contacts peut prendre quelques minutes)."\n\n"Pour ajouter des contacts, appuyez sur "<font fgcolor="#ffffffff"><b>"Menu"</b></font>", puis sur :"\n" "\n<li><font fgcolor="#ffffffff"><b>"Comptes"</b></font>" pour ajouter ou configurer un compte dont vous pourrez synchroniser les contacts vers la tablette ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Options d\'affichage"</b></font>" pour modifier les paramètres de visibilité des contacts ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nouveau contact"</b></font>" pour créer un contact ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/Exporter"</b></font>" pour importer des contacts depuis votre carte SIM ou SD."\n</li></string>
<string name="noContactsHelpTextWithSync" product="default" msgid="3017521127042216243">"Vous n\'avez aucun contact à afficher (si vous venez d\'ajouter un compte, la synchronisation des contacts peut prendre quelques minutes)."\n\n"Pour ajouter des contacts, appuyez sur "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" et sélectionnez :"\n" "\n<li><font fgcolor="#ffffffff"><b>"Comptes"</b></font>" pour ajouter ou configurer un compte dont vous pourrez synchroniser les contacts sur le téléphone ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Options d\'affichage"</b></font>" pour modifier le paramètre de visibilité des contacts ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nouveau contact"</b></font>" pour créer un contact ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/Exporter"</b></font>" pour importer des contacts depuis votre carte SIM ou SD."\n</li></string>
- <!-- syntax error in translation for noContactsNoSimHelpText (6031363021287849874) org.xmlpull.v1.XmlPullParserException: expected: /b read: font (position:END_TAG </font>@1:565 in java.io.StringReader@2e8f4fb3) -->
- <!-- syntax error in translation for noContactsNoSimHelpText (467658807711582876) org.xmlpull.v1.XmlPullParserException: expected: /b read: font (position:END_TAG </font>@1:571 in java.io.StringReader@42b988a6) -->
+ <!-- syntax error in translation for noContactsNoSimHelpText (6031363021287849874) org.xmlpull.v1.XmlPullParserException: expected: /b read: font (position:END_TAG </font>@1:565 in java.io.StringReader@3343c8b3) -->
+ <!-- syntax error in translation for noContactsNoSimHelpText (467658807711582876) org.xmlpull.v1.XmlPullParserException: expected: /b read: font (position:END_TAG </font>@1:571 in java.io.StringReader@272d7a10) -->
<string name="noContactsNoSimHelpTextWithSync" product="tablet" msgid="6222739731808897565">"Vous n\'avez aucun contact à afficher (si vous venez d\'ajouter un compte, la synchronisation des contacts peut prendre quelques minutes)."\n\n"Pour ajouter des contacts, appuyez sur "<font fgcolor="#ffffffff"><b>"Menu"</b></font>", puis sur :"\n" "\n<li><font fgcolor="#ffffffff"><b>"Comptes"</b></font>" pour ajouter ou configurer un compte dont vous pourrez synchroniser les contacts vers la tablette ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Options d\'affichage"</b></font>" pour modifier les paramètres de visibilité des contacts ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nouveau contact"</b></font>" pour créer un contact ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/Exporter"</b></font>" pour importer des contacts depuis votre carte SD."\n</li></string>
<string name="noContactsNoSimHelpTextWithSync" product="default" msgid="9040060730467973050">"Vous n\'avez aucun contact à afficher (si vous venez d\'ajouter un compte, la synchronisation des contacts peut prendre quelques minutes)."\n\n"Pour ajouter des contacts, appuyez sur "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" et sélectionnez :"\n" "\n<li><font fgcolor="#ffffffff"><b>"Comptes"</b></font>" pour ajouter ou configurer un compte dont vous pourrez synchroniser les contacts sur le téléphone ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Options d\'affichage"</b></font>" pour modifier le paramètre de visibilité des contacts ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nouveau contact"</b></font>" pour créer un contact ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/Exporter"</b></font>" pour importer des contacts depuis votre carte SD."\n</li></string>
<string name="noFavoritesHelpText" msgid="3744655776704833277">"Vous ne disposez d\'aucun favoris."\n\n"Pour ajouter un contact à la liste de favoris :"\n\n" "<li>"Appuyez sur l\'onglet "<b>"Contacts"</b>"."\n</li>" "\n<li>"Appuyez sur le contact à ajouter à vos favoris."\n</li>" "\n<li>"Appuyez sur l\'étoile en regard du nom du contact."\n</li></string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"photo du contact"</string>
<string name="description_minus_button" msgid="387136707700230172">"moins"</string>
<string name="description_plus_button" msgid="515164827856229880">"plus"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Mémoire de stockage USB indisponible"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Mémoire non disponible"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Aucune carte SD trouvée"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Mémoire de stockage USB non détectée"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Aucune mémoire stockage détectée"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Aucune carte SD n\'a été détectée."</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Recherche des données VCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Importer à partir de la carte SIM"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Importer depuis mémoire USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Importer depuis mémoire"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Importer à partir de la carte SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Exporter vers mémoire USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Exporter vers la mémoire"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Exporter vers la carte SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Partager les contacts visibles"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Importer un fichier vCard"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importer plusieurs fichiers vCard"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Importer tous les fichiers vCard"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Recherche de données VCard sur la mémoire de stockage USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Recherche de données vCard sur la mémoire de stockage"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Recherche de données VCard sur la carte SD"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Impossible d\'analyser la mémoire de stockage USB"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Échec de la recherche dans la mémoire de stockage"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Échec de l\'analyse de la carte SD"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Impossible d\'analyser la mémoire de stockage USB (Raison : \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Échec de la recherche dans la mémoire de stockage (Raison : \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Échec de l\'analyse de la carte SD (Raison : \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Erreur d\'E/S"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Mémoire insuffisante (fichier probablement trop volumineux)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Échec de l\'analyse des données VCard pour une raison inattendue"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Le format n\'est pas compatible."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Échec de l\'importation du fichier vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"Aucun fichier vCard n\'a été trouvé sur la mémoire de stockage USB."</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Aucun fichier vCard trouvé sur la mémoire de stockage"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Aucun fichier vCard trouvé sur la carte SD"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Échec de la collecte des métadonnées contenues dans le(s) fichier(s) vCard"</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Échec de l\'importation d\'un ou de plusieurs fichiers (%s)"</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Échec lors de l\'exportation des données du contact"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Échec lors de l\'exportation des données du contact."\n"Motif : \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Aucun contact exportable"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"La mémoire de stockage USB contient trop de fichiers VCard."</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"La mémoire de stockage contient trop de fichiers vCard."</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"La carte SD contient trop de fichiers VCard."</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Le nom de fichier requis est trop long (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Fichier vCard <xliff:g id="FILENAME">%s</xliff:g> exporté"</string>
@@ -339,7 +341,7 @@
<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 professionnel"</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>
@@ -353,7 +355,7 @@
<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_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>
@@ -362,7 +364,7 @@
<string name="sms_tty_tdd" msgid="6782284969132531532">"Envoyer SMS vers numéro TTY/TTD (malentendants)"</string>
<string name="sms_work_mobile" msgid="2459939960512702560">"Envoyer un SMS sur le mobile professionnel"</string>
<string name="sms_work_pager" msgid="5566924423316960597">"Envoyer un SMS vers téléavertisseur (bureau)"</string>
- <string name="sms_assistant" msgid="2773424339923116234">"Envoyer un message texte à <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Envoyer un SMS à <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
<string name="sms_mms" msgid="4069352461380762677">"Envoyer un MMS"</string>
<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>
@@ -400,15 +402,17 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Phonétique du prénom"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Phonétique 2e prénom"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Phonétique du nom de famille"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Nom phonétique"</string>
<string name="account_type_format" msgid="718948015590343010">"Contact <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
- <string name="from_account_format" msgid="687567483928582084">"de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Utiliser cette photo"</string>
<string name="contact_read_only" msgid="1203216914575723978">"Vous ne pouvez pas modifier les informations du contact <xliff:g id="SOURCE">%1$s</xliff:g> sur cet appareil."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Aucune autre information pour ce contact"</string>
<string name="display_options_sort_list_by" msgid="6080091755852211076">"Trier la liste par"</string>
<string name="display_options_sort_by_given_name" msgid="184916793466387067">"Prénom"</string>
<string name="display_options_sort_by_family_name" msgid="7857986975275712622">"Nom de famille"</string>
- <string name="display_options_view_names_as" msgid="18022868169627979">"Afficher les contacts avec"</string>
+ <string name="display_options_view_names_as" msgid="18022868169627979">"Afficher les contacts par"</string>
<string name="display_options_view_given_name_first" msgid="6968288511197363292">"Le prénom en premier"</string>
<string name="display_options_view_family_name_first" msgid="1447288164951453714">"Le nom de famille en premier"</string>
<string name="search_bar_hint" msgid="1012756309632856553">"Rechercher..."</string>
@@ -433,6 +437,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"Aucun contact sélectionné"</string>
<string name="add_field" msgid="2384260056674995230">"Ajouter un champ"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Ajouter un numéro"</string>
+ <string name="add_email" msgid="175079666329862215">"Ajouter adresse e-mail"</string>
+ <string name="add_im" msgid="5158094627521120439">"Ajouter compte chat"</string>
+ <string name="add_address" msgid="418292312672970688">"Ajouter une adresse"</string>
+ <string name="add_note" msgid="2753771325725383279">"Ajouter une remarque"</string>
+ <string name="add_website" msgid="4312391288948517344">"Ajouter un site Web"</string>
+ <string name="add_event" msgid="7488781591843886426">"Ajouter un événement"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Ajouter une relation"</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>
<string name="description_star" msgid="2605854427360036550">"favori"</string>
@@ -464,7 +476,7 @@
<string name="menu_settings" msgid="377929915873428211">"Paramètres"</string>
<string name="preference_displayOptions" msgid="1341720270148252393">"Options d\'affichage"</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="hint_findContacts" msgid="1808681193458772072">"Recherchez des contacts."</string>
+ <string name="hint_findContacts" msgid="1808681193458772072">"Recherchez des contacts"</string>
<string name="non_phone_caption" msgid="1541655052330027380">"Numéro de téléphone"</string>
<string name="non_phone_add_to_contacts" msgid="6590985286250471169">"Ajouter aux contacts"</string>
<string name="non_phone_close" msgid="7608506439725515667">"Fermer"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 9f6eb24..97b4cd7 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Zadano"</string>
<string name="removePhoto" msgid="4898105274130284565">"Ukloni fotografiju"</string>
<string name="noContacts" msgid="8579310973261953559">"Nema kontakata."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Nisu pronađeni podudarni kontakti."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Nema kontakata s telefonskim brojevima."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Samo kontakti s telefonima"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"1 kontakt s tel. brojem"</item>
<item quantity="other" msgid="3299954047880968205">"Kontakata s tel. brojevima: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Nema vidljivih kontakata s telefonskim brojevima."</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Nema kontakata s telefonskim brojevima"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 kontakt"</item>
<item quantity="other" msgid="3578469907265375314">"Broj kontakata: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Nema vidljivih kontakata"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Nema kontakata"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Nema vidljivih kontakata"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Nema kontakata sa zvjezdicom"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Nema kontakata pod: <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"1 pronađen"</item>
<item quantity="other" msgid="3852668542926965042">"Pronađeno kontakata: <xliff:g id="COUNT">%d</xliff:g>"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"Pronađeno kontakata: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Kontakti"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoriti"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telefon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Zapisnik poziva"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Zapisnik poziva je prazan"</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Izbriši zapisnik poziva"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Jeste li sigurni da želite izbrisati zapisnik poziva?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Brisanje zapisnika poziva"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Govorna pošta"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"fotografija kontakta"</string>
<string name="description_minus_button" msgid="387136707700230172">"minus"</string>
<string name="description_plus_button" msgid="515164827856229880">"plus"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Memorija USB nedostupna"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Prostor za pohranu nedostupan"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Nema SD kartice"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Memorija USB nije otkrivena"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Pohrana nije otkrivena"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Nije pronađena SD kartica"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Traženje kartice vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Uvezi sa SIM kartice"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Uvoz s USB memorije"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Uvoz iz pohrane"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Uvezi sa SD kartice"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Izvoz na USB memoriju"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Izvoz u pohranu"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Izvoz na SD karticu"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Dijeli vidljive kontakte"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Uvezi jednu vCard datoteku"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Uvoz više vCard datoteka"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Uvezi sve vCard datoteke"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Traženje vCard podataka u USB memoriji"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Traženje podataka kartice vCard u pohrani"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Traženje vCard podataka na SD kartici"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Skeniranje memorije USB nije uspjelo"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Skeniranje pohrane nije uspjelo"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Skeniranje SD kartice nije uspjelo"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Skeniranje memorije USB nije uspjelo (razlog: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Skeniranje pohrane nije uspjelo (razlog: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Skeniranje SD kartice nije uspjelo (Razlog: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"I/O pogreška"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Memorija je premala (datoteka je možda prevelika)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Analiza kartice vCard nije uspjela zbog neočekivanog razloga"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Format nije podržan."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Neuspješan uvoz vCarda"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"U USB pohrani nije pronađena vCard datoteka"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Datoteka kartice vCard nije pronađena u pohrani"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Na SD kartici nije pronađena datoteka vCard"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Neuspješno prikupljanje meta informacija danih datoteka vCard."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Uvoz jedne ili više datoteka nije uspio (%s)."</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Izvoz podataka o kontaktu nije uspio."</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Izvoz podataka o kontaktu nije uspio."\n"Razlog neuspjeha: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Nema kontakta koji je moguće izvesti"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Previše datoteka vCard u USB memoriji"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Previše datoteka kartice vCard u pohrani"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Previše vCard datoteka na SD kartici"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Obavezan naziv datoteke je predug (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Završetak izvoza <xliff:g id="FILENAME">%s</xliff:g>"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Fonetsko ime"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetsko srednje ime"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Fonetsko prezime"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Ime fonetski"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> kontakt"</string>
- <string name="from_account_format" msgid="687567483928582084">"s lokacije <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Upotrijebi ovu fotografiju"</string>
<string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g> informacije kontakta nije moguće uređivati na ovom uređaju."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Nema dodatnih informacija za ovaj kontakt"</string>
@@ -423,13 +427,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Deinstaliraj neke aplikacije"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Pokušaj ponovo nadogradnju"</string>
<string name="search_results_searching" msgid="7755623475227227314">"Pretraživanje..."</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"Prikaži odabrano"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"Pokaži sve"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"Odaberi sve"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"Poništi odabir svega"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"Nije odabran nijedan kontakt."</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"Prikaži odabrano"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"Pokaži sve"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"Odaberi sve"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"Poništi odabir svega"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"Odabran je 1 primatelj"</item>
+ <item quantity="other" msgid="4608837420986126229">"Odabrano primatelja: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"Nije odabran nijedan kontakt."</string>
<string name="add_field" msgid="2384260056674995230">"Dodaj drugo polje"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Dodajte novi tel. broj"</string>
+ <string name="add_email" msgid="175079666329862215">"Dodajte novu e-poštu"</string>
+ <string name="add_im" msgid="5158094627521120439">"Dodajte novi IM račun"</string>
+ <string name="add_address" msgid="418292312672970688">"Dodajte novu adresu"</string>
+ <string name="add_note" msgid="2753771325725383279">"Dodajte novu napomenu"</string>
+ <string name="add_website" msgid="4312391288948517344">"Dodajte novu stranicu"</string>
+ <string name="add_event" msgid="7488781591843886426">"Dodajte novi događaj"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Dodajte novi odnos"</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>
<string name="description_star" msgid="2605854427360036550">"favorit"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 3e869b8..d4dd0f9 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -79,7 +79,7 @@
<string name="invalidContactMessage" msgid="5816991830260044593">"A névjegy nem létezik."</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"Új névjegy létrehozása"</string>
<string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefon"</string>
- <string name="emailLabelsGroup" msgid="8389931313045344406">"E-mail küldése"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-mail cím"</string>
<string name="imLabelsGroup" msgid="3898238486262614027">"Azonnali üzenetküldés"</string>
<string name="postalLabelsGroup" msgid="3487738141112589324">"Cím"</string>
<string-array name="otherLabels">
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Alapértelmezett"</string>
<string name="removePhoto" msgid="4898105274130284565">"Fénykép törlése"</string>
<string name="noContacts" msgid="8579310973261953559">"Nincsenek névjegyek."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Nincsenek a keresési feltételeknek megfelelő névjegyek."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Nincsenek telefonszámot is tartalmazó névjegyek."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Csak a telefonszámmal rendelkező névjegyek"</string>
@@ -121,9 +123,8 @@
</plurals>
<string name="listTotalAllContactsZero" msgid="1889349925514589304">"Nincsenek névjegyek"</string>
<string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Nincsenek látható névjegyek"</string>
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"<xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Nincs csillaggal megjelölt névjegy"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Nincsenek névjegyek itt: <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"1 találat"</item>
<item quantity="other" msgid="3852668542926965042">"<xliff:g id="COUNT">%d</xliff:g> találat"</item>
@@ -135,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> találat"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Címtár"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Kedvencek"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telefon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Híváslista"</string>
@@ -150,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"A híváslista üres."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Híváslista törlése"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Biztosan törli a híváslistát?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Hívási napló törölve"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Hangposta"</string>
@@ -209,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"fotó a névjegyhez"</string>
<string name="description_minus_button" msgid="387136707700230172">"mínusz"</string>
<string name="description_plus_button" msgid="515164827856229880">"plusz"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Az USB-tár nem érhető el"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"A tárhely nem érhető el"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Hiányzó SD-kártya"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Nem észlelhető USB-tár"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Nem észlelhető tárhely"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Az SD-kártya nem észlelhető"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"vCard keresése"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Importálás a SIM-kártyáról"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Importálás USB-tárról"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Importálás a tárhelyről"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Importálás az SD-kártyáról"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Exportálás USB-tárra"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Exportálás a tárhelyre"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Exportálás SD-kártyára"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Látható névjegyek megosztása"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Egyetlen vCard fájl importálása"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Több vCard fájl importálása"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Az összes vCard fájl importálása"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"vCard-adatok keresése az USB-táron"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"vCard-adatok keresése a tárhelyen"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"vCard-adatok keresése az SD-kártyán"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Az USB-tár beolvasása sikertelen volt"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Nem sikerült beolvasni a tárhelyet"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Az SD-kártya beolvasása sikertelen"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Az USB-tár beolvasása sikertelen volt (A hiba oka: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Nem sikerült beolvasni a tárhelyet (a hiba oka: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Az SD-kártya beolvasása nem sikerült (oka: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"I/O hiba"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Nincs elég memória (lehet, hogy túl nagy a fájl)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Váratlan ok miatt nem sikerült a vCard szintaktikai elemzése"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"A formátum nem támogatott."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Nem sikerült a vCard importálása"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"Nem található vCard fájl az USB-táron"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Nem található vCard fájl a tárhelyen"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Nem található vCard fájl az SD-kártyán"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Nem sikerült begyűjteni a vCard fájl(ok) metaadatait."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Egy vagy több fájlt nem sikerült importálni (%s)."</string>
@@ -260,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Nem sikerült exportálni a névjegyadatokat"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Nem sikerült exportálni a névjegyadatokat."\n"A hiba oka: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Nincs exportálható névjegy"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Túl sok vCard-fájl van az USB-táron"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Túl sok vCard fájl van a tárhelyen"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Túl sok vCard fájl van az SD-kártyán"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"A fájlnév túl hosszú (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"A(z) <xliff:g id="FILENAME">%s</xliff:g> exportálása befejeződött"</string>
@@ -398,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Utónév fonetikusan"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Második utónév fonetikusan"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Vezetéknév fonetikusan"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Név fonetikusan"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> névjegy"</string>
- <string name="from_account_format" msgid="687567483928582084">"<xliff:g id="SOURCE">%1$s</xliff:g> fiókból"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Fotó felhasználása"</string>
<string name="contact_read_only" msgid="1203216914575723978">"A(z) <xliff:g id="SOURCE">%1$s</xliff:g> névjegyadatai nem szerkeszthetők ezen az eszközön."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Nincsenek további adatok ennél a névjegynél"</string>
@@ -421,13 +427,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Távolítson el néhány alkalmazást"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Verziófrissítés újrapróbálása"</string>
<string name="search_results_searching" msgid="7755623475227227314">"Keresés..."</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"Kiválasztottak megjelenítése"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"Összes megjelenítése"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"Összes kijelölése"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"Összes kijelölés megszüntetése"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"Nincs kijelölt névjegy."</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"Kiválasztottak megjelenítése"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"Összes megjelenítése"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"Összes kijelölése"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"Összes kijelölés megszüntetése"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"1 címzett kiválasztva"</item>
+ <item quantity="other" msgid="4608837420986126229">"<xliff:g id="COUNT">%d</xliff:g> címzett kiválasztva"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"Nincs kijelölt névjegy."</string>
<string name="add_field" msgid="2384260056674995230">"Más mező hozzáadása"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Új telefonszám"</string>
+ <string name="add_email" msgid="175079666329862215">"Új e-mail hozzáadása"</string>
+ <string name="add_im" msgid="5158094627521120439">"Új IM-fiók hozzáadása"</string>
+ <string name="add_address" msgid="418292312672970688">"Új cím hozzáadása"</string>
+ <string name="add_note" msgid="2753771325725383279">"Új megjegyzés"</string>
+ <string name="add_website" msgid="4312391288948517344">"Új webhely hozzáadása"</string>
+ <string name="add_event" msgid="7488781591843886426">"Új esemény hozzáadása"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Új kapcsolat"</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>
<string name="description_star" msgid="2605854427360036550">"kedvenc"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index b78a501..8418108 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Bawaan"</string>
<string name="removePhoto" msgid="4898105274130284565">"Hapus foto"</string>
<string name="noContacts" msgid="8579310973261953559">"Tidak ada kenalan."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Tidak ditemukan kenalan yang cocok."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Tidak ada kenalan dengan nomor telepon."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Hanya kenalan dengan telepon"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"1 kenalan dengan nomor telepon"</item>
<item quantity="other" msgid="3299954047880968205">"<xliff:g id="COUNT">%d</xliff:g> kenalan dengan nomor telepon"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Tidak ada kenalan dengan nomor telepon"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Tidak ada kenalan dengan nomor telepon"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 kenalan"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> kenalan"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Tidak ada kenalan yang terlihat"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Tidak ada kenalan"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Tidak ada kenalan yang terlihat"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Tidak ada kenalan yang berkilau bintangnya"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Tidak ada kenalan di <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"Ada 1"</item>
<item quantity="other" msgid="3852668542926965042">"Ada <xliff:g id="COUNT">%d</xliff:g>"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"Ada <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Kenalan"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favorit"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telepon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Log panggilan"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Log panggilan kosong."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Hapus log panggilan"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Apakah Anda yakin ingin menghapus log panggilan?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Membersihkan log panggilan"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Kotak Pesan"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"foto kenalan"</string>
<string name="description_minus_button" msgid="387136707700230172">"minus"</string>
<string name="description_plus_button" msgid="515164827856229880">"plus"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Penyimpanan USB tidak tersedia"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Penyimpanan tidak tersedia"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Tidak ada kartu SD"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Tidak ada penyimpanan USB yang terdeteksi"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Penyimpanan tidak terdeteksi"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Tidak ada kartu SD yang terdeteksi"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Menelusuri vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Impor dari kartu SIM"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Mengimpor dari penyimpanan USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Impor dari penyimpanan"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Impor dari kartu SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Ekspor ke penyimpanan USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Ekspor ke penyimpanan"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Ekspor ke kartu SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Bagikan kenalan yang terlihat"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Impor satu berkas vCard"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Impor beberapa berkas vCard"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Impor semua berkas vCard"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Menelusuri data vCard dalam penyimpanan USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Menelusuri data vCard dalam penyimpanan"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Menelusuri data vCard pada kartu SD."</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Memindai penyimpanan USB gagal"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Gagal memindai penyimpanan"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Kartu SD gagal dipindai"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Memindai penyimpanan USB gagal (Alasan: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Gagal memindai penyimpanan (Alasan: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Kartu SD gagal dipindai (Alasan: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Galat I/O"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Memori tidak memadai (berkas mungkin terlalu besar)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Gagal melakukan parse pada vCard karena alasan yang tidak diharapkan"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Format tidak didukung."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Gagal mengimpor vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"Tidak ada berkas vCard yang ditemukan pada penyimpanan USB"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Tidak ditemukan berkas vCard dalam penyimpanan"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Tidak ada berkas vCard yang ditemukan pada kartu SD"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Gagal mengumpulkan informasi meta dari berkas vCard yang diberikan."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Satu berkas atau lebih gagal diimpor (%s)"</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Gagal mengekspor data kenalan"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Gagal mengekspor data kenalan."\n"Alasan kegagalan: \"<xliff:g id="FAIL_REASON">%s</xliff:g>:"</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Tidak ada kenalan yang dapat diekspor"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Terlalu banyak berkas vCard dalam penyimpanan USB"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Terlalu banyak berkas vCard dalam penyimpanan"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Terlalu banyak berkas vCard pada kartu SD"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Nama berkas yang diperlukan terlalu panjang (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Selesai mengekspor <xliff:g id="FILENAME">%s</xliff:g>"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Nama depan fonetik"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Nama tengah fonetik"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Nama keluarga fonetik"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Nama fonetik"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> kenalan"</string>
- <string name="from_account_format" msgid="687567483928582084">"dari <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Gunakan foto ini"</string>
<string name="contact_read_only" msgid="1203216914575723978">"Informasi kenalan <xliff:g id="SOURCE">%1$s</xliff:g> tidak dapat diedit pada perangkat ini."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Tidak ada informasi tambahan untuk kenalan ini"</string>
@@ -423,13 +427,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Copot pemasangan beberapa aplikasi"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Coba peningkatan versi sekali lagi"</string>
<string name="search_results_searching" msgid="7755623475227227314">"Menelusuri..."</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"Tampilkan yang dipilih"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"Tampilkan semua"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"Pilih semua"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"Batal pilih semua"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"Tidak ada kenalan yang dipilih."</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"Tampilkan yang dipilih"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"Tampilkan semua"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"Pilih semua"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"Batal pilih semua"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"1 penerima dipilih"</item>
+ <item quantity="other" msgid="4608837420986126229">"<xliff:g id="COUNT">%d</xliff:g> penerima dipilih"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"Tidak ada kenalan yang dipilih."</string>
<string name="add_field" msgid="2384260056674995230">"Tambahkan bidang lain"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Menambah no. tlp. baru"</string>
+ <string name="add_email" msgid="175079666329862215">"Menambah email baru"</string>
+ <string name="add_im" msgid="5158094627521120439">"Menambah akun IM baru"</string>
+ <string name="add_address" msgid="418292312672970688">"Menambah alamat baru"</string>
+ <string name="add_note" msgid="2753771325725383279">"Menambah catatan baru"</string>
+ <string name="add_website" msgid="4312391288948517344">"Menambah situs baru"</string>
+ <string name="add_event" msgid="7488781591843886426">"Menambah acara baru"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Menambah hubungan baru"</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>
<string name="description_star" msgid="2605854427360036550">"favorit"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 25b6479..a64e592 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -95,6 +95,7 @@
<string name="default_ringtone" msgid="9099988849649827972">"Predefinita"</string>
<string name="removePhoto" msgid="4898105274130284565">"Rimuovi foto"</string>
<string name="noContacts" msgid="8579310973261953559">"Nessun contatto."</string>
+ <string name="noGroups" msgid="8614664663561385253">"Nessun gruppo."</string>
<string name="noMatchingContacts" msgid="4266283206853990471">"Nessun contatto corrispondente trovato."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Nessun contatto con numeri di telefono."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Solo contatti con numeri di tel."</string>
@@ -114,18 +115,15 @@
<item quantity="one" msgid="3015357862286673986">"1 contatto con numero di telefono"</item>
<item quantity="other" msgid="3299954047880968205">"<xliff:g id="COUNT">%d</xliff:g> contatti con numeri di telefono"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Nessun contatto con numeri di telefono visibile"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Nessun contatto con numeri di telefono"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 contatto"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> contatti"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Nessun contatto visibile"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Nessun contatto"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Nessun contatto visibile"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Nessun contatto aggiunto a Speciali"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Nessun contatto in <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"1 trovato"</item>
<item quantity="other" msgid="3852668542926965042">"<xliff:g id="COUNT">%d</xliff:g> trovati"</item>
@@ -137,6 +135,7 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> trovati"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Contatti"</string>
+ <string name="contactsGroupsLabel" msgid="2841971472518003524">"Gruppi"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Preferiti"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telefono"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Chiamate"</string>
@@ -152,6 +151,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Il registro chiamate è vuoto."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Cancella registro chiamate"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Cancellare il registro chiamate?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Cancellazione registro chiamate"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Segreteria"</string>
@@ -211,32 +211,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"foto contatto"</string>
<string name="description_minus_button" msgid="387136707700230172">"meno"</string>
<string name="description_plus_button" msgid="515164827856229880">"più"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Archivio USB non disponibile"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Archivio non disponibile"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Nessuna scheda SD"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Nessun archivio USB rilevato"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Nessun archivio rilevato"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Nessuna scheda SD rilevata"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Ricerca vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Importa da scheda SIM"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Importa da archivio USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Importa da archivio"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Importa da scheda SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Esporta in archivio USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Esporta in archivio"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Esporta su scheda SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Condividi contatti visibili"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Importa un file vCard"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importa più file vCard"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Importa tutti i file vCard"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Ricerca di dati vCard nell\'archivio USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Ricerca di dati vCard nell\'archivio"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Ricerca dati vCard su scheda SD"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Scansione dell\'archivio USB non riuscita"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Scansione dell\'archivio non riuscita"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Analisi scheda SD non riuscita"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Scansione dell\'archivio USB non riuscita (motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Scansione dell\'archivio non riuscita (motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Analisi scheda SD non riuscita (motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Errore I/O"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Memoria insufficiente (il file potrebbe essere di dimensioni eccessive)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Impossibile analizzare la vCard per motivi imprevisti"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Il formato non è supportato."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Importazione vCard non riuscita"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"Nessun file vCard trovato nell\'archivio USB"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Nessun file vCard trovato nell\'archivio"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Nessun file vCard trovato sulla scheda SD"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Raccolta dei metadati dei file vCard forniti non riuscita."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Impossibile importare uno o più file (%s)."</string>
@@ -262,7 +262,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Esportazione dati contatti non riuscita"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Esportazione dati contatti non riuscita."\n"Motivo dell\'errore: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Nessun contatto esportabile"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Troppi file vCard nell\'archivio USB"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Troppi file vCard nell\'archivio"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Troppi dati vCard sulla scheda SD"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Il nome file richiesto è troppo lungo (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Esportazione di <xliff:g id="FILENAME">%s</xliff:g> terminata"</string>
@@ -400,8 +400,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Nome fonetico fornito"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Secondo nome fonetico"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Cognome fonetico"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Nome fonetico"</string>
<string name="account_type_format" msgid="718948015590343010">"Contatto da <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
- <string name="from_account_format" msgid="687567483928582084">"da <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Utilizza questa foto"</string>
<string name="contact_read_only" msgid="1203216914575723978">"Informazioni del contatto da <xliff:g id="SOURCE">%1$s</xliff:g> non modificabili su questo dispositivo."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Nessuna informazione aggiuntiva per questo contatto"</string>
@@ -433,6 +435,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"Nessun contatto selezionato."</string>
<string name="add_field" msgid="2384260056674995230">"Aggiungi un altro campo"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Nuovo n. telefono"</string>
+ <string name="add_email" msgid="175079666329862215">"Nuova email"</string>
+ <string name="add_im" msgid="5158094627521120439">"Nuovo account IM"</string>
+ <string name="add_address" msgid="418292312672970688">"Nuovo indirizzo"</string>
+ <string name="add_note" msgid="2753771325725383279">"Nuova nota"</string>
+ <string name="add_website" msgid="4312391288948517344">"Nuovo sito web"</string>
+ <string name="add_event" msgid="7488781591843886426">"Nuovo evento"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Nuova relazione"</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>
<string name="description_star" msgid="2605854427360036550">"preferiti"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 5fa32b3..7a28703 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"ברירת מחדל"</string>
<string name="removePhoto" msgid="4898105274130284565">"הסר תמונה"</string>
<string name="noContacts" msgid="8579310973261953559">"אין אנשי קשר."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"לא נמצאו אנשי קשר תואמים."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"אין אנשי קשר עם מספרי טלפון."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"רק אנשי קשר עם מספרי טלפון"</string>
@@ -134,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> נמצאו"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"אנשי קשר"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"מועדפים"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"טלפון"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"יומן שיחות"</string>
@@ -149,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"יומן השיחות ריק."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"נקה את יומן השיחות"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"האם אתה בטוח שברצונך לנקות את יומן השיחות?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"ניקוי יומן שיחות"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"דואר קולי"</string>
@@ -208,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"תמונה של איש קשר"</string>
<string name="description_minus_button" msgid="387136707700230172">"חיסור"</string>
<string name="description_plus_button" msgid="515164827856229880">"ועוד"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"אמצעי אחסון מסוג USB אינו זמין"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"אמצעי אחסון אינו זמין"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"אין כרטיס SD"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"לא זוהה אמצעי אחסון מסוג USB"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"לא זוהה אמצעי אחסון"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"לא אותר כרטיס SD"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"מחפש vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"ייבא מכרטיס SIM"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"ייבא מאמצעי אחסון מסוג USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"ייבא מאמצעי אחסון"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"ייבא מכרטיס SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"ייצא לאמצעי אחסון מסוג USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"ייצא לאמצעי אחסון"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"ייצא לכרטיס SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"שתף אנשי קשר גלויים"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"ייבא קובץ אחד של vCard"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"ייבא קובצי vCard מרובים"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"ייבא את כל קובצי vCard"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"מחפש נתוני vCard באמצעי אחסון מסוג USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"מחפש נתוני vCard באמצעי אחסון"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"מחפש נתוני vCard בכרטיס SD"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"סריקת אמצעי אחסון מסוג USB נכשלה"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"סריקת אמצעי אחסון נכשלה"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"נכשלה סריקת כרטיס SD"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"סריקת אמצעי אחסון מסוג USB נכשלה (סיבה: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"סריקת אמצעי אחסון נכשלה (סיבה: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"נכשלה סריקת כרטיס SD (סיבה: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"שגיאת קלט/פלט"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"אין מספיק זיכרון (ייתכן שהקובץ גדול מדי)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"נכשל ניתוח vCard עקב סיבה לא צפויה"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"הפורמט אינו נתמך."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"נכשל ייבוא vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"לא נמצא קובץ vCard באמצעי אחסון מסוג USB"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"לא נמצא קובץ vCard באמצעי האחסון"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"לא נמצא קובץ vCard בכרטיס ה-SD"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"נכשל איסוף מידע-על מקובצי vCard נתונים."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"נכשל הייבוא של קובץ אחד או יותר (%s)."</string>
@@ -259,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"נכשל ייצוא הנתונים של איש הקשר"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"נכשל ייצוא הנתונים של איש קשר."\n"הסיבה לכשל: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"אין איש קשר שניתן לייצא"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"קובצי vCard רבים מדי באמצעי אחסון מסוג USB"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"קובצי vCard רבים מדי באמצעי האחסון"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"קובצי vCard רבים מדי בכרטיס ה-SD"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"שם הקובץ הדרוש ארוך מדי (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"הייצוא של <xliff:g id="FILENAME">%s</xliff:g> הסתיים"</string>
@@ -397,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"שם פרטי פונטי"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"שם אמצעי פונטי"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"שם משפחה פונטי"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"שם פונטי"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g>איש קשר"</string>
- <string name="from_account_format" msgid="687567483928582084">"מ-<xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"השתמש בתמונה זו"</string>
<string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g> פרטי איש הקשר אינם ניתנים לעריכה במכשיר זה."</string>
<string name="no_contact_details" msgid="6754415338321837001">"אין מידע נוסף על איש קשר זה"</string>
@@ -420,13 +427,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"הסר התקנה של יישומים מסוימים"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"נסה שוב לשדרג"</string>
<string name="search_results_searching" msgid="7755623475227227314">"מחפש..."</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"הצג פריטים שנבחרו"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"הצג הכל"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"בחר הכל"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"בטל את הבחירה של הכל"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"לא נבחרו אנשי קשר."</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"הצג פריטים שנבחרו"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"הצג הכל"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"בחר הכל"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"בטל בחירה של הכל"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"נבחר נמען אחד"</item>
+ <item quantity="other" msgid="4608837420986126229">"<xliff:g id="COUNT">%d</xliff:g> נמענים נבחרו"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"לא נבחרו אנשי קשר."</string>
<string name="add_field" msgid="2384260056674995230">"הוסף שדה נוסף"</string>
+ <string name="add_phone" msgid="4421904942555210013">"הוסף מספר טלפון חדש"</string>
+ <string name="add_email" msgid="175079666329862215">"הוסף דוא\"ל חדש"</string>
+ <string name="add_im" msgid="5158094627521120439">"הוסף חשבון IM חדש"</string>
+ <string name="add_address" msgid="418292312672970688">"הוסף כתובת חדשה"</string>
+ <string name="add_note" msgid="2753771325725383279">"הוסף הערה חדשה"</string>
+ <string name="add_website" msgid="4312391288948517344">"הוסף אתר חדש"</string>
+ <string name="add_event" msgid="7488781591843886426">"הוסף אירוע חדש"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"הוסף קשר חדש"</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>
<string name="description_star" msgid="2605854427360036550">"מועדף"</string>
diff --git a/res/values-ja/donottranslate_config.xml b/res/values-ja/donottranslate_config.xml
index c5d3aea..7f53722 100644
--- a/res/values-ja/donottranslate_config.xml
+++ b/res/values-ja/donottranslate_config.xml
@@ -32,4 +32,7 @@
<!-- 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 8e92c4b..9f2f257 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"プリセット着信音"</string>
<string name="removePhoto" msgid="4898105274130284565">"写真を削除"</string>
<string name="noContacts" msgid="8579310973261953559">"連絡先がありません。"</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"一致する連絡先が見つかりません。"</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"電話番号付きの連絡先はありません。"</string>
<string name="showFilterPhones" msgid="4184858075465653970">"電話番号のある連絡先のみ"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"電話番号のある連絡先1件"</item>
<item quantity="other" msgid="3299954047880968205">"電話番号のある連絡先<xliff:g id="COUNT">%d</xliff:g>件"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"表示可能な電話番号付きの連絡先はありません"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"電話番号付きの連絡先はありません"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"連絡先1件"</item>
<item quantity="other" msgid="3578469907265375314">"連絡先<xliff:g id="COUNT">%d</xliff:g>件"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"表示可能な連絡先はありません"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"連絡先はありません"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"表示可能な連絡先はありません"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"スター付きの連絡先はありません"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"<xliff:g id="NAME">%s</xliff:g>の連絡先はありません"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"1件見つかりました"</item>
<item quantity="other" msgid="3852668542926965042">"<xliff:g id="COUNT">%d</xliff:g>件見つかりました"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g>件見つかりました"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"連絡先"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"お気入り"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"電話"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"通話履歴"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"通話履歴なし"</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"通話履歴を消去"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"通話履歴を消去してもよろしいですか?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"通話履歴の消去中"</string>
<string name="imei" msgid="3045126336951684285">"IMEI(端末識別番号)"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"ボイスメール"</string>
@@ -172,7 +174,7 @@
<string name="noContactsNoSimHelpText" product="default" msgid="467658807711582876">"表示できる連絡先がありません。"\n\n"連絡先を追加するには、まず"<font fgcolor="#ffffffff"><b>"MENU"</b></font>"キーを押し:"\n\n<li>"電話との同期が可能な連絡先のアカウントを追加または設定する場合は["<font fgcolor="#ffffffff"><b>"アカウント"</b></font>"]をタップします"\n</li>\n<li>"新しい連絡先を最初から作成する場合は["<font fgcolor="#ffffffff"><b>"連絡先を新規登録"</b></font>"]をタップします"\n</li>" "\n<li>"SDカードから連絡先をインポートする場合は["<font fgcolor="#ffffffff"><b>"インポート/エクスポート"</b></font>"]をタップします"\n</li></string>
<string name="noContactsNoSimHelpTextWithSync" product="tablet" msgid="6222739731808897565">"表示できる連絡先がありません(アカウントを追加した場合は、連絡先が同期されるまでに数分かかることがあります)。"\n\n"連絡先を追加するには、まず"<font fgcolor="#ffffffff"><b>"MENU"</b></font>"キーを押し:"\n\n<li>"タブレットと同期する連絡先のアカウントを追加または設定する場合は["<font fgcolor="#ffffffff"><b>"アカウント"</b></font>"]をタップします"\n</li>\n<li>"表示される連絡先を変更するには["<font fgcolor="#ffffffff"><b>"表示オプション"</b></font>"]をタップします"\n</li>" "\n<li>"新しい連絡先を最初から作成する場合は["<font fgcolor="#ffffffff"><b>"連絡先を新規登録"</b></font>"]をタップします"\n</li>" "\n<li>"SDカードから連絡先をインポートする場合は["<font fgcolor="#ffffffff"><b>"インポート/エクスポート"</b></font>"]をタップします"\n</li></string>
<string name="noContactsNoSimHelpTextWithSync" product="default" msgid="9040060730467973050">"表示できる連絡先がありません(アカウントを追加した場合は、連絡先が同期されるまでに数分かかることがあります)。"\n\n"連絡先を追加するには、まず"<font fgcolor="#ffffffff"><b>"MENU"</b></font>"キーを押し:"\n\n<li>"電話との同期が可能な連絡先のアカウントを追加または設定する場合は["<font fgcolor="#ffffffff"><b>"アカウント"</b></font>"]をタップします"\n</li>\n<li>"表示される連絡先を変更するには["<font fgcolor="#ffffffff"><b>"表示オプション"</b></font>"]をタップします"\n</li>" "\n<li>"新しい連絡先を最初から作成する場合は["<font fgcolor="#ffffffff"><b>"連絡先を新規登録"</b></font>"]をタップします"\n</li>" "\n<li>"SDカードから連絡先をインポートする場合は["<font fgcolor="#ffffffff"><b>"インポート/エクスポート"</b></font>"]をタップします"\n</li></string>
- <string name="noFavoritesHelpText" msgid="3744655776704833277">"お気に入りはありません。"\n\n"お気に入りのリストに連絡先を追加するには: "\n\n" "<li>"["<b>"連絡先"</b>"]タブをタップします"\n</li>" "\n<li>"お気に入りに追加する連絡先をタップします"\n</li>" "\n<li>"連絡先名の横にあるスターをタップします"\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"お気に入りはありません。"\n\n"お気に入りのリストに連絡先を追加するには: "\n\n<li>"["<b>"連絡先"</b>"]タブをタップします"\n</li>" "\n<li>"お気に入りに追加する連絡先をタップします"\n</li>" "\n<li>"連絡先名の横にあるスターをタップします"\n</li></string>
<string name="liveFolder_all_label" msgid="5961411940473276616">"すべての連絡先"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"スター付き"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"電話"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"連絡先の写真"</string>
<string name="description_minus_button" msgid="387136707700230172">"マイナス"</string>
<string name="description_plus_button" msgid="515164827856229880">"プラス"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"USBストレージ使用不可"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"ストレージ使用不可"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"SDカードがありません"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"USBストレージがありません"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"ストレージがありません"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"SDカードを検出できませんでした"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"vCardを検索中"</string>
<string name="import_from_sim" msgid="3859272228033941659">"SIMカードからインポート"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"USBストレージからインポート"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"ストレージからインポート"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"SDカードからインポート"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"USBストレージにエクスポート"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"ストレージにエクスポート"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"SDカードにエクスポート"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"表示可能な連絡先を共有"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"vCardファイルを1つインポート"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"複数のvCardファイルをインポート"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"すべてのvCardファイルをインポート"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"USBストレージ内でvCardデータを検索中"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"ストレージ内でvCardデータを検索中"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"SDカードのvCardデータを検索しています"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"USBストレージのスキャンエラー"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"ストレージのスキャンエラー"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"SDカードのスキャンに失敗しました"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"USBストレージをスキャンできませんでした(理由: 「<xliff:g id="FAIL_REASON">%s</xliff:g>」)"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"ストレージをスキャンできませんでした(理由: 「<xliff:g id="FAIL_REASON">%s</xliff:g>」)"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"SDカードのスキャンに失敗しました(理由: <xliff:g id="FAIL_REASON">%s</xliff:g>)"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"送受信エラー"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"メモリが不足しています(ファイルが大きすぎる可能性があります)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"予期しない理由によりvCardの解析に失敗しました"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"このフォーマットはサポートされません。"</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"vCardをインポートできませんでした。"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"USBストレージ内にvCardファイルが見つかりません"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"ストレージ内にvCardファイルが見つかりません"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"SDカード内にvCardファイルが見つかりません"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"指定されたvCardファイルのメタ情報を取得できませんでした。"</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"1つ以上のファイルをインポートできませんでした(%s)。"</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"連絡先データのエクスポートに失敗しました"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"連絡先データのエクスポートに失敗しました。"\n"理由: 「<xliff:g id="FAIL_REASON">%s</xliff:g>」"</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"エクスポートできる連絡先がありません"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"USBストレージ内のvCardファイルが多すぎます"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"ストレージ内のvCardファイルが多すぎます"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"SDカードのvCardファイルが多すぎます"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"指定したファイル名が長すぎます(「<xliff:g id="FILENAME">%s</xliff:g>」)"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"<xliff:g id="FILENAME">%s</xliff:g>のエクスポートが終了しました"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"名のよみがな"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"ミドルネームのよみがな"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"姓のよみがな"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"よみがな"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g>からの連絡先"</string>
- <string name="from_account_format" msgid="687567483928582084">"<xliff:g id="SOURCE">%1$s</xliff:g>からの連絡先"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"この写真を使用"</string>
<string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g>からの連絡先情報はこの携帯端末では編集できません。"</string>
<string name="no_contact_details" msgid="6754415338321837001">"この連絡先の詳細情報はありません"</string>
@@ -433,6 +437,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"連絡先が選択されていません。"</string>
<string name="add_field" msgid="2384260056674995230">"別のフィールドを追加"</string>
+ <string name="add_phone" msgid="4421904942555210013">"新しい電話番号を追加"</string>
+ <string name="add_email" msgid="175079666329862215">"新しいメールを追加"</string>
+ <string name="add_im" msgid="5158094627521120439">"新規IMアカウントを追加"</string>
+ <string name="add_address" msgid="418292312672970688">"新しい住所を追加"</string>
+ <string name="add_note" msgid="2753771325725383279">"新しいメモを追加"</string>
+ <string name="add_website" msgid="4312391288948517344">"新しいサイトを追加"</string>
+ <string name="add_event" msgid="7488781591843886426">"新しいイベントを追加"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"新しい関係を追加"</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>
<string name="description_star" msgid="2605854427360036550">"お気に入り"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 153997c..5ccbf47 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -64,7 +64,7 @@
<string name="readOnlyContactWarning" msgid="1390849295342594265">"읽기 전용 계정의 주소록은 삭제할 수 없지만 주소록 목록에서 숨길 수는 있습니다."</string>
<string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"연락처에 여러 계정의 정보가 들어 있습니다. 읽기 전용 계정의 정보는 주소록 목록에서 숨길 수 있지만 삭제할 수는 없습니다."</string>
<string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"이 연락처를 삭제하면 여러 계정의 정보가 삭제됩니다."</string>
- <string name="deleteConfirmation" msgid="811706994761610640">"연락처가 삭제됩니다."</string>
+ <string name="deleteConfirmation" msgid="811706994761610640">"이 연락처를 삭제합니다."</string>
<string name="menu_done" msgid="796017761764190697">"완료"</string>
<string name="menu_doNotSave" msgid="58593876893538465">"취소"</string>
<string name="editContact_title_edit" msgid="7678695190666836093">"연락처 수정"</string>
@@ -75,7 +75,7 @@
<string name="label_ringtone" msgid="8833166825330686244">"벨소리"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"이름(소리나는 대로)"</string>
<string name="ghostData_company" msgid="5414421120553765775">"회사"</string>
- <string name="ghostData_title" msgid="7496735200318496110">"제목"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"직함"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"연락처가 없습니다."</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"새 연락처 만들기"</string>
<string name="phoneLabelsGroup" msgid="6468091477851199285">"전화"</string>
@@ -95,9 +95,11 @@
<string name="default_ringtone" msgid="9099988849649827972">"기본값"</string>
<string name="removePhoto" msgid="4898105274130284565">"사진 삭제"</string>
<string name="noContacts" msgid="8579310973261953559">"주소록이 없습니다."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"일치하는 연락처가 없습니다."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"전화번호가 포함된 주소록이 없습니다."</string>
- <string name="showFilterPhones" msgid="4184858075465653970">"전화가 있는 연락처만"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"전화번호가 있는 연락처만"</string>
<string name="showFilterPhonesDescrip" msgid="6644443248815191067">"전화번호가 있는 연락처만 표시"</string>
<string name="headerContactGroups" msgid="2426134991932503843">"표시할 연락처 선택"</string>
<plurals name="groupDescrip">
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"전화번호가 포함된 연락처 1개"</item>
<item quantity="other" msgid="3299954047880968205">"전화번호가 포함된 연락처 <xliff:g id="COUNT">%d</xliff:g>개"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"전화번호가 포함된, 표시할 수 있는 주소록이 없습니다."</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"전화번호가 포함된 주소록이 없습니다."</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"연락처 1개"</item>
<item quantity="other" msgid="3578469907265375314">"연락처 <xliff:g id="COUNT">%d</xliff:g>개"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"표시할 수 있는 주소록이 없습니다."</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"주소록이 없습니다."</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"표시할 수 있는 주소록이 없습니다."</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"별표 주소록이 없습니다."</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"<xliff:g id="NAME">%s</xliff:g>에 주소록이 없습니다."</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"1개를 찾았습니다."</item>
<item quantity="other" msgid="3852668542926965042">"<xliff:g id="COUNT">%d</xliff:g>개를 찾았습니다."</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g>개를 찾았습니다."</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"주소록"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"즐겨찾기"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"휴대전화"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"통화기록"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"통화기록이 없습니다."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"통화 기록 지우기"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"통화 기록을 삭제하시겠습니까?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"통화기록 지우기"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"음성사서함"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"주소록 사진"</string>
<string name="description_minus_button" msgid="387136707700230172">"빼기"</string>
<string name="description_plus_button" msgid="515164827856229880">"더하기"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"USB 저장소 사용 불가능"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"저장장치 없음"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"SD 카드 없음"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"USB 저장소가 없습니다."</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"저장장치가 없습니다."</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"SD 카드가 발견되지 않았습니다."</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"vCard 검색"</string>
<string name="import_from_sim" msgid="3859272228033941659">"SIM 카드에서 가져오기"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"USB 저장소에서 가져오기"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"저장장치에서 가져오기"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"SD 카드에서 가져오기"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"USB 저장소로 내보내기"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"저장공간으로 내보내기"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"SD 카드로 내보내기"</string>
- <string name="share_visible_contacts" msgid="890150378880783797">"표시되는 연락처 공유"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"표시되는 연락처 모두 공유"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"vCard 파일 한 개 가져오기"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"vCard 파일 여러 개 가져오기"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"모든 vCard 파일 가져오기"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"USB 저장소에서 vCard 데이터 검색"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"저장장치에서 vCard 데이터 검색"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"SD 카드의 vCard 데이터 검색"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"USB 저장소 스캔 실패"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"저장장치 스캔 실패"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"SD 카드 스캔 실패"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"USB 저장소 스캔 실패(이유: \'<xliff:g id="FAIL_REASON">%s</xliff:g>\')"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"저장장치 스캔 실패(이유: \'<xliff:g id="FAIL_REASON">%s</xliff:g>\')"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"SD 카드 스캔 실패(이유: \'<xliff:g id="FAIL_REASON">%s</xliff:g>\')"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"I/O 오류"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"메모리가 부족합니다. 파일이 너무 크기 때문일 수 있습니다."</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"예기치 못한 이유로 인해 vCard를 구문분석하지 못했습니다."</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"지원되지 않는 형식입니다."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"vCard를 가져오지 못했습니다."</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"vCard 파일이 USB 저장소에 없습니다."</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"저장공간에 vCard 파일이 없습니다."</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"SD 카드에 VCard 파일이 없습니다."</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"지정한 vCard 파일에 대한 메타 정보를 수집하지 못했습니다."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"하나 이상의 파일을 가져오지 못했습니다(%s)."</string>
@@ -248,7 +250,7 @@
<string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g> 가져오는 중"</string>
<string name="reading_vcard_failed_title" msgid="2162610359561887043">"vCard 데이터를 읽지 못했습니다."</string>
<string name="reading_vcard_canceled_title" msgid="1770608329958463131">"vCard 데이터 읽기가 취소되었습니다."</string>
- <string name="importing_vcard_finished_title" msgid="3341541727268747967">"<xliff:g id="FILENAME">%s</xliff:g> 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="6367906965439777280">"<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>
@@ -262,24 +264,24 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"연락처 데이터를 내보내지 못했습니다."</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"연락처 데이터를 내보내지 못했습니다."\n"실패 이유: \'<xliff:g id="FAIL_REASON">%s</xliff:g>\'"</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"내보낼 수 있는 연락처가 없습니다."</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"USB 저장소에 vCard 파일이 너무 많습니다."</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"저장공간에 vCard 파일이 너무 많습니다."</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"SD 카드에 vCard 파일이 너무 많습니다."</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"필수 파일 이름이 너무 깁니다(\'<xliff:g id="FILENAME">%s</xliff:g>\')."</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"<xliff:g id="FILENAME">%s</xliff:g> 내보내기 완료됨"</string>
- <string name="exporting_vcard_canceled_title" msgid="1827672399438062140">"<xliff:g id="FILENAME">%s</xliff:g> 가져오기가 취소됨"</string>
+ <string name="exporting_vcard_canceled_title" msgid="1827672399438062140">"<xliff:g id="FILENAME">%s</xliff:g> 내보내기가 취소됨"</string>
<string name="exporting_contact_list_title" msgid="9072240631534457415">"연락처 데이터 내보내기"</string>
<string name="exporting_contact_list_message" msgid="5640326540405486055">"연락처 데이터를 \'<xliff:g id="FILE_NAME">%s</xliff:g>\'(으)로 내보내는 중"</string>
<string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"내보내기를 초기화하지 못했습니다. \'<xliff:g id="EXACT_REASON">%s</xliff:g>\'"</string>
<string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"내보내는 중에 오류가 발생했습니다. \'<xliff:g id="EXACT_REASON">%s</xliff:g>\'"</string>
<string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"데이터베이스 정보를 가져오지 못했습니다."</string>
- <string name="composer_has_no_exportable_contact" product="tablet" msgid="5161491059051198932">"내보낼 수 있는 연락처가 없습니다. 태블릿에 실제로 연락처가 있다면 일부 데이터 제공업체에서 모든 연락처를 휴대전화 외부로 내보내지 못하도록 금지했을 수 있습니다."</string>
+ <string name="composer_has_no_exportable_contact" product="tablet" msgid="5161491059051198932">"내보낼 수 있는 연락처가 없습니다. 태블릿에 실제로 연락처가 있다면 일부 데이터 제공업체에서 모든 연락처를 외부로 내보내지 못하도록 금지했을 수 있습니다."</string>
<string name="composer_has_no_exportable_contact" product="default" msgid="322344221706924358">"내보낼 수 있는 연락처가 없습니다. 휴대전화에 실제로 연락처가 있다면 일부 데이터 제공업체에서 모든 연락처를 휴대전화 외부로 내보내지 못하도록 금지했을 수 있습니다."</string>
<string name="composer_not_initialized" msgid="8041534450748388843">"vCard 작성기가 바르게 초기화되지 않았습니다."</string>
<string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"\'<xliff:g id="FILE_NAME">%s</xliff:g>\'을(를) 열 수 없습니다. <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
<string name="exporting_contact_list_progress" msgid="560522409559101193">"연락처 <xliff:g id="CURRENT_NUMBER">%s</xliff:g>개(총 <xliff:g id="TOTAL_NUMBER">%s</xliff:g>개) 내보내는 중"</string>
- <string name="cancel_import_confirmation_title" msgid="5578683596010294836">"vCard 가져오기 취소"</string>
+ <string name="cancel_import_confirmation_title" msgid="5578683596010294836">"vCard 가져오기 취소 중"</string>
<string name="cancel_import_confirmation_message" msgid="8560937090143057107">"<xliff:g id="FILENAME">%s</xliff:g> 가져오기를 취소하시겠습니까?"</string>
- <string name="cancel_export_confirmation_title" msgid="6516467140276768528">"vCard 내보내기 취소"</string>
+ <string name="cancel_export_confirmation_title" msgid="6516467140276768528">"vCard 내보내기 취소 중"</string>
<string name="cancel_export_confirmation_message" msgid="1392976902396351957">"<xliff:g id="FILENAME">%s</xliff:g> 내보내기를 취소하시겠습니까?"</string>
<string name="cancel_vcard_import_or_export_failed" msgid="7096533244663846810">"vCard 가져오기/내보내기 취소 실패"</string>
<string name="search_settings_description" msgid="2675223022992445813">"연락처 명단"</string>
@@ -292,7 +294,7 @@
<string name="quickcontact_remember_choice" msgid="5964536411579749424">"이 선택사항 저장"</string>
<string name="quickcontact_missing_name" msgid="5590266114306996632">"알 수 없음"</string>
<string name="quickcontact_no_data" msgid="2098000859125253675">"데이터가 없습니다."</string>
- <string name="quickcontact_clear_defaults_description" msgid="3792792870662989100">"기본 정보 지우기"</string>
+ <string name="quickcontact_clear_defaults_description" msgid="3792792870662989100">"기본 설정 지우기"</string>
<string name="quickcontact_clear_defaults_caption" msgid="4287306111861545753">"연락처의 기본 설정:"</string>
<string name="quickcontact_clear_defaults_button" msgid="8728754360205289059">"지우기"</string>
<string name="menu_accounts" msgid="8499114602017077970">"계정"</string>
@@ -313,7 +315,7 @@
<string name="type_short_work" msgid="4925330752504537861">"W"</string>
<string name="type_short_pager" msgid="2613818970827594238">"P"</string>
<string name="type_short_other" msgid="5669407180177236769">"O"</string>
- <string name="dialog_new_contact_account" msgid="9044704073286262197">"계정에서 연락처 만들기"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"연락처 추가할 계정 선택하기"</string>
<string name="menu_sync_remove" msgid="3266725887008450161">"동기화 그룹 삭제"</string>
<string name="dialog_sync_add" msgid="8267045393119375803">"동기화 그룹 추가"</string>
<string name="display_more_groups" msgid="2682547080423434170">"그룹 더보기..."</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"이름(소리나는 대로)"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"중간 이름(소리나는 대로)"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"성(소리나는 대로)"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"이름(소리나는 대로)"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> 연락처"</string>
- <string name="from_account_format" msgid="687567483928582084">"출처: <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"사진 사용"</string>
<string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g> 연락처 정보는 이 기기에서 수정할 수 없습니다."</string>
<string name="no_contact_details" msgid="6754415338321837001">"연락처에 대한 추가 정보가 없습니다."</string>
@@ -433,6 +437,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"선택한 연락처가 없습니다."</string>
<string name="add_field" msgid="2384260056674995230">"다른 입력란 추가"</string>
+ <string name="add_phone" msgid="4421904942555210013">"새 전화번호 추가"</string>
+ <string name="add_email" msgid="175079666329862215">"새 이메일 추가"</string>
+ <string name="add_im" msgid="5158094627521120439">"새 메신저 계정 추가"</string>
+ <string name="add_address" msgid="418292312672970688">"새 주소 추가"</string>
+ <string name="add_note" msgid="2753771325725383279">"새 메모 추가"</string>
+ <string name="add_website" msgid="4312391288948517344">"새 웹사이트 추가"</string>
+ <string name="add_event" msgid="7488781591843886426">"새 일정 추가"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"새 관계 추가"</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>
<string name="description_star" msgid="2605854427360036550">"즐겨찾기"</string>
@@ -443,8 +455,8 @@
</plurals>
<string name="local_invisible_directory" msgid="6046691709127661065">"기타"</string>
<string name="aggregation_suggestion_join_dialog_title" msgid="5276699501316246253">"연락처 통합"</string>
- <string name="aggregation_suggestion_join_dialog_message" msgid="3842757977671434836">"현재 연락처를 선택한 주소록에 통합하시겠습니까?"</string>
- <string name="aggregation_suggestion_edit_dialog_title" msgid="1064042382692091314">"선택한 주소록 수정"</string>
+ <string name="aggregation_suggestion_join_dialog_message" msgid="3842757977671434836">"이 연락처와 선택한 연락처를 통합하시겠습니까?"</string>
+ <string name="aggregation_suggestion_edit_dialog_title" msgid="1064042382692091314">"선택한 연락처 수정"</string>
<string name="aggregation_suggestion_edit_dialog_message" msgid="6549585283910518095">"선택한 연락처를 수정하시겠습니까? 지금까지 입력하신 정보는 복사됩니다."</string>
<string name="menu_copyContact" msgid="4401683725471696686">"내 주소록에 복사"</string>
<string name="contact_directory_description" msgid="683398073603909119">"디렉토리 <xliff:g id="TYPE">%1$s</xliff:g>"</string>
@@ -464,7 +476,7 @@
<string name="menu_settings" msgid="377929915873428211">"설정"</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="hint_findContacts" msgid="1808681193458772072">"주소록 찾기"</string>
+ <string name="hint_findContacts" msgid="1808681193458772072">"연락처 찾기"</string>
<string name="non_phone_caption" msgid="1541655052330027380">"전화번호"</string>
<string name="non_phone_add_to_contacts" msgid="6590985286250471169">"주소록에 추가"</string>
<string name="non_phone_close" msgid="7608506439725515667">"닫기"</string>
@@ -472,15 +484,15 @@
<string name="date_year_toggle" msgid="7356532842767854606">"출생연도 입력 선택"</string>
<string name="social_widget_label" msgid="6378905543028924592">"연락처"</string>
<string name="social_widget_loading" msgid="3697996166985327861">"로드 중..."</string>
- <string name="contacts_unavailable_create_contact" msgid="7014525713871959208">"새 주소록 만들기"</string>
+ <string name="contacts_unavailable_create_contact" msgid="7014525713871959208">"새 연락처 만들기"</string>
<string name="contacts_unavailable_add_account" msgid="7911101713860139754">"계정에 로그인"</string>
<string name="contacts_unavailable_import_contacts" msgid="4456440183590517471">"파일에서 주소록 가져오기"</string>
<string name="create_group_dialog_title" msgid="6874527142828424475">"새 그룹 만들기"</string>
<string name="create_group_item_label" msgid="5218022006186243310">"[새 그룹 만들기]"</string>
- <string name="rename_group_dialog_title" msgid="3765299704290513289">"그룹 이름 바꾸기"</string>
+ <string name="rename_group_dialog_title" msgid="3765299704290513289">"그룹 이름 변경"</string>
<string name="delete_group_dialog_title" msgid="7368429698398624427">"그룹 삭제"</string>
- <string name="delete_group_dialog_message" msgid="295063284548750881">"\'<xliff:g id="GROUP_LABEL">%1$s</xliff:g>\' 그룹을 삭제하시겠습니까(주소록은 삭제되지 않음)?"</string>
- <string name="toast_join_with_empty_contact" msgid="5015189525953438968">"다른 연락처와 통합하기 전에 연락처 이름을 입력하세요."</string>
+ <string name="delete_group_dialog_message" msgid="295063284548750881">"\'<xliff:g id="GROUP_LABEL">%1$s</xliff:g>\' 그룹을 삭제하시겠습니까? (연락처는 삭제되지 않음)"</string>
+ <string name="toast_join_with_empty_contact" msgid="5015189525953438968">"다른 연락처와 통합하기 전에 통합할 연락처 이름을 입력하세요."</string>
<string name="indicator_joined_contact" msgid="3321049349627022128">"통합된 연락처"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"텍스트 복사됨"</string>
<string name="cancel_confirmation_dialog_title" msgid="3950463632415908534">"변경사항 취소"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 11c0912..1e063e4 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Numatytasis"</string>
<string name="removePhoto" msgid="4898105274130284565">"Pašalinti nuotrauką"</string>
<string name="noContacts" msgid="8579310973261953559">"Adresatų nėra."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Nerasta atitinkančių adresatų."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Nėra adresatų su telefono numeriais."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Tik adresatai su telefono numeriais"</string>
@@ -134,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"Rasta <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Adresinė"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Adresynas"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telefonas"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Skambučių žurnalas"</string>
@@ -149,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Skambučių žurnalas tuščias."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Išvalyti skambučių žurnalą"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Ar tikrai norite išvalyti skambučių žurnalą?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Valomas skambučių žurnalas"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Balso paštas"</string>
@@ -208,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"adresato nuotrauka"</string>
<string name="description_minus_button" msgid="387136707700230172">"minus"</string>
<string name="description_plus_button" msgid="515164827856229880">"plius"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"USB atmintinė nepasiekiama"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Saugykla neprieinama"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Nėra SD kortelės"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Neaptikta jokia USB atmintinė"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Neaptikta jokių saugyklų"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"SD kortelė neaptikta"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Ieškoma „vCard“ kortelės"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Importuoti iš SIM kortelės"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Import. iš USB atmintinės"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Importuoti iš saugyklos"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Importuoti iš SD kortelės"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Eksport. į USB atmintinę"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Eksportuoti į saugyklą"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Eksportuoti į SD kortelę"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Bendrinti matomus adresatus"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Importuoti vieną „vCard“ failą"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importuoti kelis „vCard“ failus"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Importuoti visus „VCard“ kortelės failus"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Ieškoma el. vizitinės kortelės duomenų USB atmintinėje"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Ieškoma el. vizitinės kortelės duomenų USB atmintinėje"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"SD kortelėje ieškoma „vCard“ duomenų"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Nepavyko nuskaityti USB atmintinės"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Nepavyko nuskaityti saugyklos"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"SD kortelės nuskaitymas nepavyko"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Nepavyko nuskaityti USB atmintinės (Priežastis: „<xliff:g id="FAIL_REASON">%s</xliff:g>“)"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Nepavyko nuskaityti saugyklos (priežastis: „<xliff:g id="FAIL_REASON">%s</xliff:g>“)"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"SD kortelės nuskaitymas nepavyko (priežastis: „<xliff:g id="FAIL_REASON">%s</xliff:g>“)"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Įvesties / išvesties klaida"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Nepakanka atminties (failas gali būti per didelis)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Dėl netikėtos priežasties nepavyko išanalizuoti „vCard“"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Formatas nepalaikomas."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Nepavyko import. el. vizitinės kortelės"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"USB atmintinėje nerasta jokių el. vizitinių kortelių failų"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Saugykloje nerasta el. vizitinės kortelės failų"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"SD kortelėje nerasta jokių el. vizitinių kortelių failų"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Nepavyko surinkti nurodyto (-ų) el. vizitinės kortelės failo (-ų) metainformacijos."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Nepavyko importuoti vieno ar daugiau failų (%s)."</string>
@@ -259,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Nepavyko eksportuoti adresatų duomenų"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Nepavyko eksportuoti adresato duomenų."\n"Trikties priežastis: „<xliff:g id="FAIL_REASON">%s</xliff:g>“"</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Nėra eksportuojamo adresato"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Per daug el. vizitinės kortelės failų USB atmintinėje"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Per daug el. vizitinės kortelės failų saugykloje"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Per daug „vCard“ failų SD kortelėje"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Reikalingo failo pavadinimas per ilgas („<xliff:g id="FILENAME">%s</xliff:g>“)"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Baigta eksportuoti <xliff:g id="FILENAME">%s</xliff:g>"</string>
@@ -397,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Suteiktas fonetinis vardas"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetinis antrasis vardas"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Fonetinė pavardė"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Fonetinis vardas"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> adresatas"</string>
- <string name="from_account_format" msgid="687567483928582084">"nuo <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Naudoti šią nuotrauką"</string>
<string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g> adresato informacijos šiame įrenginyje redaguoti negalima."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Nėra papildomos informacijos apie šį adresatą"</string>
@@ -420,13 +427,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Pašalinti kai kurias programas"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Bandyti naujovinti iš naujo"</string>
<string name="search_results_searching" msgid="7755623475227227314">"Ieškoma..."</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"Rodyti pasirinktus"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"Rodyti viską"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"Pasirinkti visus"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"Atšaukti visų pasirinkimą"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"Nepasirinkote kontaktų."</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"Rodyti pasirinktus"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"Rodyti visus"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"Pasirinkti visus"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"Atšaukti visų pasirinkimą"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"Pasirinktas vienas gavėjas"</item>
+ <item quantity="other" msgid="4608837420986126229">"Pasirinkta gavėjų: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"Nepasirinkote kontaktų."</string>
<string name="add_field" msgid="2384260056674995230">"Pridėti kitą lauką"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Pridėti naują tel. nr."</string>
+ <string name="add_email" msgid="175079666329862215">"Prid. n. el. pšt. adr."</string>
+ <string name="add_im" msgid="5158094627521120439">"Pridėti naują TP pask."</string>
+ <string name="add_address" msgid="418292312672970688">"Pridėti naują adresą"</string>
+ <string name="add_note" msgid="2753771325725383279">"Pridėti naują pastabą"</string>
+ <string name="add_website" msgid="4312391288948517344">"Pridėti naują svetainę"</string>
+ <string name="add_event" msgid="7488781591843886426">"Pridėti naują įvykį"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Pridėti naujus santyk."</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>
<string name="description_star" msgid="2605854427360036550">"įtraukti į adresyną"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index b5d597a..59668ab 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Noklusējums"</string>
<string name="removePhoto" msgid="4898105274130284565">"Noņemt fotoattēlu"</string>
<string name="noContacts" msgid="8579310973261953559">"Nav kontaktpersonu."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Nav atrasta neviena atbilstoša kontaktpersona."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Nav nevienas kontaktpersonas ar tālruņa numuru."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Tikai kontaktpersonas ar tālruņiem"</string>
@@ -134,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"Atrastas <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Kontaktpersonas"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Izlase"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Zvanīt"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Zvanu žurnāls"</string>
@@ -149,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Zvanu žurnāls ir tukšs."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Notīrīt zvanu žurnālu"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Vai tiešām vēlaties notīrīt zvanu žurnālu?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Zvanu žurnāla tīrīšana"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Balss pasts"</string>
@@ -208,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"kontaktpersonas fotoattēls"</string>
<string name="description_minus_button" msgid="387136707700230172">"mīnuss"</string>
<string name="description_plus_button" msgid="515164827856229880">"pluss"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"USB atmiņa nav pieejama"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"USB atmiņa nav pieejama"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Nav SD kartes"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Nav noteikta USB atmiņa"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Nav atrasta neviena USB. atm."</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"SD karte nav noteikta."</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"vCard faila meklēšana"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Importēt no SIM kartes"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Import. no USB atmiņas"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Importēt no USB atmiņas"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Importēt no SD kartes"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Eksport. uz USB atmiņu"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Eksportēt uz USB atmiņu"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Eksportēt uz SD karti"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Kopīgot redzamās kontaktpersonas"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Importēt vienu vCard failu"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importēt vairākus vCard failus"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Importēt visus vCard failus"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Notiek vCard datu meklēšana USB atmiņā"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Notiek vCard datu meklēšana USB atmiņā."</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Notiek vCard datu meklēšana SD kartē"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"USB atmiņas skenēšana neizdevās"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Neizdevās skenēt USB atmiņu"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Neizdevās skenēt SD karti."</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"USB atmiņas skenēšana neizdevās (iemesls: <xliff:g id="FAIL_REASON">%s</xliff:g>)"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"USB atmiņas skenēšana neizdevās (iemesls: <xliff:g id="FAIL_REASON">%s</xliff:g>)"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"SD kartes skenēšana neizdevās (cēlonis: “<xliff:g id="FAIL_REASON">%s</xliff:g>”)."</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Ievades/izvades kļūda"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Atmiņā nepietiek vietas (iespējams, fails ir pārāk liels)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Neparedzēta iemesla dēļ neizdevās parsēt vCard failu."</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Šis formāts nav atbalstīts."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"vCard importēšana neizdevās."</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"USB atmiņā nav atrasts neviens vCard fails."</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"USB atmiņā nav atrasts neviens vCard fails."</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"SD kartē nav atrasts neviens vCard fails."</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Neizdevās iegūt meta informāciju par konkrēto(-ajiem) vCard failu(-iem)."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Neizdevās importēt vienu vai vairākus failus (%s)."</string>
@@ -259,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Neizdevās eksportēt kontaktpersonas datus."</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Neizdevās eksportēt kontaktpersonu datus."\n"Kļūmes cēlonis: “<xliff:g id="FAIL_REASON">%s</xliff:g>”"</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Nav eksportējamu kontaktpersonas datu."</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"USB atmiņā ir pārāk daudz vCard failu."</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"USB atmiņā ir pārāk daudz vCard failu."</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"SD kartē ir pārāk daudz vCard failu."</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Faila nosaukums ir pārāk garš (“<xliff:g id="FILENAME">%s</xliff:g>”)."</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Faila <xliff:g id="FILENAME">%s</xliff:g> eksportēšana ir pabeigta"</string>
@@ -397,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Vārda izruna"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Otrā vārda izruna"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Uzvārda izruna"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Vārda izruna"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> kontaktpersona"</string>
- <string name="from_account_format" msgid="687567483928582084">"no <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Izmantot šo fotoattēlu"</string>
<string name="contact_read_only" msgid="1203216914575723978">"Kontaktinformāciju no pakalpojuma <xliff:g id="SOURCE">%1$s</xliff:g> šajā ierīcē nevar rediģēt."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Nav pieejama papildu informācija par šo kontaktpersonu."</string>
@@ -420,13 +427,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Atinstalēt dažas lietojumprogrammas"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Mēģināt jaunināt vēlreiz"</string>
<string name="search_results_searching" msgid="7755623475227227314">"Notiek meklēšana..."</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"Parādīt atlasi"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"Rādīt visu"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"Atlasīt visu"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"Noņemt atlasi visam"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"Nav atlasīta neviena kontaktpersona."</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"Rādīt atlasi"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"Rādīt visus"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"Atlasīt visas"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"Noņemt atlasi visam"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"Ir atlasīts 1 adresāts"</item>
+ <item quantity="other" msgid="4608837420986126229">"Ir atlasīti <xliff:g id="COUNT">%d</xliff:g> adresāti"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"Nav atlasīta neviena kontaktpersona."</string>
<string name="add_field" msgid="2384260056674995230">"Pievienot vēl vienu lauku"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Piev. jaunu tālr. nr."</string>
+ <string name="add_email" msgid="175079666329862215">"Piev. jaunu e-pastu"</string>
+ <string name="add_im" msgid="5158094627521120439">"Piev. jaunu t. ziņ. k."</string>
+ <string name="add_address" msgid="418292312672970688">"Pievienot jaunu adresi"</string>
+ <string name="add_note" msgid="2753771325725383279">"Piev. jaunu piezīmi"</string>
+ <string name="add_website" msgid="4312391288948517344">"Pievienot jaunu vietni"</string>
+ <string name="add_event" msgid="7488781591843886426">"Piev. jaunu notikumu"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Piev. jaunu saistību"</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>
<string name="description_star" msgid="2605854427360036550">"izlase"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 5688446..c02662d 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Standardvalg"</string>
<string name="removePhoto" msgid="4898105274130284565">"Fjern bilde"</string>
<string name="noContacts" msgid="8579310973261953559">"Ingen kontakter."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Fant ingen kontakter."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Ingen kontakter med telefonnummer."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Kun kontakter med telefon"</string>
@@ -134,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> funnet"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Kontakter"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoritter"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telefon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Logg"</string>
@@ -149,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Anropsloggen er tom."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Tøm samtalelogg"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Er du sikker på at du vil tømme samtaleloggen?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Tømming av anropslogg"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Telefonsvarer"</string>
@@ -161,12 +166,12 @@
<string name="simContacts_title" msgid="27341688347689769">"Kontakter på SIM-kort"</string>
<string name="noContactsHelpTextWithSyncForCreateShortcut" msgid="801504710275614594">"Du har ingen kontakter å vise. (Hvis du nettopp har lagt til en konto, kan det ta noen minutter å synkronisere kontaktene.)"</string>
<string name="noContactsHelpTextForCreateShortcut" msgid="3081286388667108335">"Du har ingen kontakter å vise."</string>
- <!-- syntax error in translation for noContactsHelpText (6450346791169710787) org.xmlpull.v1.XmlPullParserException: expected: /li read: font (position:END_TAG </font>@1:292 in java.io.StringReader@3ced0338) -->
- <!-- syntax error in translation for noContactsHelpText (7633826236417884130) org.xmlpull.v1.XmlPullParserException: expected: /li read: font (position:END_TAG </font>@1:293 in java.io.StringReader@6c6e70c7) -->
+ <!-- syntax error in translation for noContactsHelpText (6450346791169710787) org.xmlpull.v1.XmlPullParserException: expected: /li read: font (position:END_TAG </font>@1:292 in java.io.StringReader@457471e0) -->
+ <!-- syntax error in translation for noContactsHelpText (7633826236417884130) org.xmlpull.v1.XmlPullParserException: expected: /li read: font (position:END_TAG </font>@1:293 in java.io.StringReader@5fe04cbf) -->
<string name="noContactsHelpTextWithSync" product="tablet" msgid="2364665535969139880">"Du har ingen kontakter å vise. (Hvis du nylig la til en konto, kan det ta noen minutter å synkronisere kontaktene.)"\n\n"Slik legger du til kontakter: Trykk på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>", og trykk deretter på:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Kontoer"</b></font>" for å legge til eller konfigurere en konto med kontakter som kan synkroniseres til nettbrettet"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Visningsalternativer"</b></font>" for å endre hvilke kontakter som vises"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" for å opprette en ny kontakt fra grunnen av"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/Eksporter"</b></font>" for å importere kontakter fra SIM- eller SD-kort"\n</li></string>
<string name="noContactsHelpTextWithSync" product="default" msgid="3017521127042216243">"Du har ingen kontakter å vise. (Hvis du nylig la til en konto, kan det ta noen minutter å synkronisere kontaktene.)"\n\n"Slik legger du til kontakter: Trykk på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" og trykk deretter på: "\n" "\n<li><font fgcolor="#ffffffff"><b>"Kontoer "</b></font>" for å legge til eller konfigurere en konto med kontakter som kan synkroniseres til telefonen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Visningsalternativer"</b></font>" for å endre hvilke kontakter som vises"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" for å opprette en ny kontakt"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importér/Eksportér"</b></font>" for å importere kontakter fra SIM- eller SD-kort"\n</li></string>
- <!-- syntax error in translation for noContactsNoSimHelpText (6031363021287849874) org.xmlpull.v1.XmlPullParserException: expected: /li read: font (position:END_TAG </font>@1:297 in java.io.StringReader@2e8f4fb3) -->
- <!-- syntax error in translation for noContactsNoSimHelpText (467658807711582876) org.xmlpull.v1.XmlPullParserException: expected: /li read: font (position:END_TAG </font>@1:297 in java.io.StringReader@42b988a6) -->
+ <!-- syntax error in translation for noContactsNoSimHelpText (6031363021287849874) org.xmlpull.v1.XmlPullParserException: expected: /li read: font (position:END_TAG </font>@1:297 in java.io.StringReader@7ecec0c5) -->
+ <!-- syntax error in translation for noContactsNoSimHelpText (467658807711582876) org.xmlpull.v1.XmlPullParserException: expected: /li read: font (position:END_TAG </font>@1:297 in java.io.StringReader@37d2068d) -->
<string name="noContactsNoSimHelpTextWithSync" product="tablet" msgid="6222739731808897565">"Du har ingen kontakter å vise. (Hvis du nylig la til en konto, kan det ta noen minutter å synkronisere kontaktene.)"\n\n"Slik legger du til kontakter: Trykk på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>", og trykk deretter på: "\n" "\n<li><font fgcolor="#ffffffff"><b>"Kontoer"</b></font>" for å legge til eller konfigurere en konto med kontakter som kan synkroniseres til nettbrettet"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Visningsalternativer"</b></font>" for å endre hvilke kontakter som vises"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" for å opprette en ny kontakt fra grunnen av"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/eksporter"</b></font>" for å importere kontakter fra SD-kortet"\n</li></string>
<string name="noContactsNoSimHelpTextWithSync" product="default" msgid="9040060730467973050">"Du har ingen kontakter å vise. (Hvis du nylig la til en konto, kan det ta noen minutter å synkronisere kontaktene.)"\n\n"Slik legger du til kontakter: Trykk på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" og trykk deretter på: "\n" "\n<li><font fgcolor="#ffffffff"><b>"Kontoer "</b></font>" for å legge til eller konfigurere en konto med kontakter som kan synkroniseres til telefonen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Visningsalternativer"</b></font>" for å endre hvilke kontakter som vises"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" for å opprette en ny kontakt"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importér/eksportér"</b></font>" for å importere kontakter fra SD-kortet"\n</li></string>
<string name="noFavoritesHelpText" msgid="3744655776704833277">"Du har ingen favoritter."\n\n"Slik legger du til en kontakt i favorittlisten:"\n\n" "<li>"Trykk på fanen "<b>"Kontakter"</b>" "\n</li>" "\n<li>"Trykk på kontakten du vil legge til i favoritter"\n</li>" "\n<li>"Trykk på stjernen ved siden av kontaktnavnet"\n</li></string>
@@ -208,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"kontaktens bilde"</string>
<string name="description_minus_button" msgid="387136707700230172">"minusknapp"</string>
<string name="description_plus_button" msgid="515164827856229880">"plussknapp"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"USB-lagring utilgj."</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Lagring utilgjengelig"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Mangler minnekort"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Finner ikke USB-lagring"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Ingen lagring oppdaget"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Fant ikke noe minnekort"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Leter etter VCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Importér fra SIM-kort"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Importér fra USB-lagr."</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Importér fra lagring"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Importér fra minnekort"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Eksportér til USB-lagr."</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Eksportér til lagring"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Eksportér til minnekort"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Del synlige kontakter"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Importer én VCard-fil"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importer flere vCard-filer"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Importer alle vCard-filer"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Søker etter vCard-data i USB-lagring"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Søker etter vCard-data i lagring"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Leter etter VCard-data på minnekort"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Skanning av USB-lagring mislyktes"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Skanning av lagring mislyktes"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Kunne ikke scanne minnekort"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Skanning av USB-lagring mislyktes (årsak: <xliff:g id="FAIL_REASON">%s</xliff:g>)"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Skanning av lagring mislyktes (årsak: <xliff:g id="FAIL_REASON">%s</xliff:g>)"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Kunne ikke skanne minnekort (grunn: «<xliff:g id="FAIL_REASON">%s</xliff:g>»)"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Inn/ut-feil (årsak: «FAIL_REASON»)"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Ikke tilstrekkelig minne (filen kan være for stor)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Kan ikke analysere VCard av uventet årsak"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Formatet støttes ikke."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Kunne ikke importere vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"Finner ingen vCard-fil i USB-lagring"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Finner ingen vCard-fil på lagringsenheten"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Fant ingen vCard-fil på SD-kortet"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Kan ikke hente inn metainformasjon for de(n) aktuelle vCard-filen(e)."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Importeringen av én eller flere filer mislyktes (%s)"</string>
@@ -259,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Kunne ikke eksportere kontaktlisten"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Eksport av kontaktdata mislyktes"\n"Årsak til feil: «<xliff:g id="FAIL_REASON">%s</xliff:g>»"</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Det finnes ingen eksporterbar kontakt."</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"For mange vCard-filer på USB-lagring"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"For mange vCard-filer på lagringsenheten"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"For mange VCard-datafiler på minnekortet"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"For langt filnavn kreves («<xliff:g id="FILENAME">%s</xliff:g>»)"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Eksport av <xliff:g id="FILENAME">%s</xliff:g> er fullført"</string>
@@ -285,7 +290,7 @@
<string name="call_disambig_title" msgid="1911302597959335178">"Ring med"</string>
<string name="sms_disambig_title" msgid="4675399294513152364">"Send SMS med"</string>
<string name="make_primary" msgid="5829291915305113983">"Husk dette valget"</string>
- <string name="quickcontact_missing_app" msgid="4600366393134289038">"Ingen programmer som kan utføre denne handlingen ble funnet"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"Ingen applikasjoner som kan utføre denne handlingen ble funnet"</string>
<string name="quickcontact_remember_choice" msgid="5964536411579749424">"Husk dette valget"</string>
<string name="quickcontact_missing_name" msgid="5590266114306996632">"Ukjent"</string>
<string name="quickcontact_no_data" msgid="2098000859125253675">"Ingen data"</string>
@@ -397,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Fonetisk fornavn"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetisk mellomnavn"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Fonetisk etternavn"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Fonetisk navn"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g>-kontakt"</string>
- <string name="from_account_format" msgid="687567483928582084">"fra <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Bruk dette bildet"</string>
<string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g>-kontaktinformasjon kan ikke redigeres på denne enheten."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Ingen utfyllende informasjon for denne kontakten"</string>
@@ -417,7 +424,7 @@
<string name="locale_change_in_progress" msgid="7583992153091537467">"Kontaktlisten er oppdatert med nytt språk."</string>
<string name="upgrade_in_progress" msgid="474511436863451061">"Kontaktlisten er under oppdatering."</string>
<string name="upgrade_out_of_memory" msgid="6153384328042175667">"Kontaktene oppgraderes."\n\n"Oppgraderingsprosessen krever omtrent <xliff:g id="SIZE_IN_MEGABYTES">%s</xliff:g> MB intern lagringsplass."\n\n"Velg ett av følgende alternativer:"</string>
- <string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Avinstaller noen programmer"</string>
+ <string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Avinstaller noen applikasjoner"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Prøv å oppgradere på nytt"</string>
<string name="search_results_searching" msgid="7755623475227227314">"Søker ..."</string>
<string name="menu_display_selected" msgid="6470001164297969034">"Vis valgte"</string>
@@ -430,6 +437,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"Ingen kontakter valgt."</string>
<string name="add_field" msgid="2384260056674995230">"Legg til et annet felt"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Legg til nytt tlf.nr."</string>
+ <string name="add_email" msgid="175079666329862215">"Legg til ny e-post"</string>
+ <string name="add_im" msgid="5158094627521120439">"Legg til nettpratkonto"</string>
+ <string name="add_address" msgid="418292312672970688">"Legg til ny adresse"</string>
+ <string name="add_note" msgid="2753771325725383279">"Legg til ny merknad:"</string>
+ <string name="add_website" msgid="4312391288948517344">"Legg til nytt nettsted"</string>
+ <string name="add_event" msgid="7488781591843886426">"Legg til ny aktivitet"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Legg til nytt forhold"</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>
<string name="description_star" msgid="2605854427360036550">"favoritt"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 5798075..d33e633 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Standaard"</string>
<string name="removePhoto" msgid="4898105274130284565">"Foto verwijderen"</string>
<string name="noContacts" msgid="8579310973261953559">"Geen contacten."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Kan geen overeenkomende contacten vinden."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Geen contacten met telefoonnummers."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Alleen contacten met tel.nr."</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"1 contact met telefoonnummer"</item>
<item quantity="other" msgid="3299954047880968205">"<xliff:g id="COUNT">%d</xliff:g> contacten met telefoonnummers"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Geen zichtbare contacten met telefoonnummers"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Geen contacten met telefoonnummers"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 contact"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> contacten"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Geen zichtbare contacten"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Geen contacten"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Geen zichtbare contacten"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Geen contacten met ster"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Geen contacten in <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"1 gevonden"</item>
<item quantity="other" msgid="3852668542926965042">"<xliff:g id="COUNT">%d</xliff:g> gevonden"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> gevonden"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Contact"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoriet"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telefoon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Gesprek"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Gesprekken is leeg"</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Oproeplogboek wissen"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Weet u zeker dat u het oproeplogboek wilt wissen?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Oproeplogboek wissen"</string>
<string name="imei" msgid="3045126336951684285">"IMEI-nummer"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Voicemail"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"contactfoto"</string>
<string name="description_minus_button" msgid="387136707700230172">"min"</string>
<string name="description_plus_button" msgid="515164827856229880">"plus"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"USB-opslag niet beschikb."</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Opslag niet beschikbaar"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Geen SD-kaart"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Geen USB-opslag gevonden"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Geen opslag gedetecteerd"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Geen SD-kaart gedetecteerd"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Zoeken naar vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Importeren van SIM-kaart"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Import. uit USB-opslag"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Importeren uit opslag"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Importeren van SD-kaart"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Export. naar USB-opslag"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Exporteren naar opslag"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Exporteren naar SD-kaart"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Zichtbare contacten delen"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Eén vCard-bestand importeren"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Meerdere vCard-bestanden importeren"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Alle vCard-bestanden importeren"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Zoeken naar vCard-gegevens in USB-opslag"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Zoeken naar vCard-gegevens in opslag"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Zoeken naar vCard-gegevens op SD-kaart"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Scannen van USB-opslag is mislukt"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Scannen van opslag is mislukt"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Scannen van SD-kaart is mislukt"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Scannen van USB-opslag is mislukt (reden: \'<xliff:g id="FAIL_REASON">%s</xliff:g>\')"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Scannen van USB-opslag is mislukt (reden: \'<xliff:g id="FAIL_REASON">%s</xliff:g>\')"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Scannen van SD-kaart is mislukt: (Reden: \'<xliff:g id="FAIL_REASON">%s</xliff:g>\')"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"I/O-fout"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Onvoldoende geheugen (het bestand is mogelijk te groot)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Parseren van vCard is mislukt om onbekende reden"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"De indeling wordt niet ondersteund."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Kan vCard niet importeren"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"Geen vCard-bestand gevonden in USB-opslag"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Geen vCard-bestand gevonden in opslag"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Geen vCard-bestand gevonden op SD-kaart"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Verzamelen van metagegevens van betreffende vCard-bestanden is mislukt."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Een of meer bestanden kunnen niet worden geïmporteerd (%s)"</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Exporteren van contactgegevens mislukt"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Exporteren van contactgegevens mislukt."\n"Reden voor de fout: \'<xliff:g id="FAIL_REASON">%s</xliff:g>\'"</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Er is geen contact dat geëxporteerd kan worden"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Te veel vCard-bestanden in de USB-opslag"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Te veel vCard-bestanden in opslag"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Te veel vCard-gegevens op de SD-kaart"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Vereiste bestandsnaam is te lang (\'<xliff:g id="FILENAME">%s</xliff:g>\')"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Exporteren van <xliff:g id="FILENAME">%s</xliff:g> voltooid"</string>
@@ -288,7 +290,7 @@
<string name="call_disambig_title" msgid="1911302597959335178">"Bellen met"</string>
<string name="sms_disambig_title" msgid="4675399294513152364">"Sms\'en met"</string>
<string name="make_primary" msgid="5829291915305113983">"Deze keuze onthouden"</string>
- <string name="quickcontact_missing_app" msgid="4600366393134289038">"Er is geen toepassing gevonden om deze actie uit te voeren"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"Er is geen app gevonden om deze actie uit te voeren"</string>
<string name="quickcontact_remember_choice" msgid="5964536411579749424">"Deze keuze onthouden"</string>
<string name="quickcontact_missing_name" msgid="5590266114306996632">"Onbekend"</string>
<string name="quickcontact_no_data" msgid="2098000859125253675">"Geen gegevens"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Fonetische roepnaam"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetische tweede voornaam"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Fonetische achternaam"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Fonetisch gespelde naam"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> contact"</string>
- <string name="from_account_format" msgid="687567483928582084">"van <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Deze foto gebruiken"</string>
<string name="contact_read_only" msgid="1203216914575723978">"Contactgegevens van <xliff:g id="SOURCE">%1$s</xliff:g> kunnen niet worden bewerkt op dit apparaat."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Geen extra gegevens voor dit contact"</string>
@@ -420,7 +424,7 @@
<string name="locale_change_in_progress" msgid="7583992153091537467">"Lijst met contacten wordt bijgewerkt om de gewijzigde taal te weerspiegelen."</string>
<string name="upgrade_in_progress" msgid="474511436863451061">"Lijst met contactpersonen wordt bijgewerkt."</string>
<string name="upgrade_out_of_memory" msgid="6153384328042175667">"Contacten worden bijgewerkt. "\n\n"Voor het upgradeproces is ongeveer <xliff:g id="SIZE_IN_MEGABYTES">%s</xliff:g> MB interne telefoonopslag vereist."\n\n"Kies een van de volgende opties."</string>
- <string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Verwijder enkele toepassingen"</string>
+ <string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Verwijder enkele apps"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Upgrade opnieuw proberen"</string>
<string name="search_results_searching" msgid="7755623475227227314">"Zoeken..."</string>
<string name="menu_display_selected" msgid="6470001164297969034">"Selectie weergeven"</string>
@@ -433,6 +437,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"Geen contacten geselecteerd."</string>
<string name="add_field" msgid="2384260056674995230">"Nog een veld toevoegen"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Nieuw telefoonnummer"</string>
+ <string name="add_email" msgid="175079666329862215">"Nieuw e-mailadres"</string>
+ <string name="add_im" msgid="5158094627521120439">"Nieuw IM-account"</string>
+ <string name="add_address" msgid="418292312672970688">"Nieuw adres"</string>
+ <string name="add_note" msgid="2753771325725383279">"Nieuwe opmerking"</string>
+ <string name="add_website" msgid="4312391288948517344">"Nieuwe website"</string>
+ <string name="add_event" msgid="7488781591843886426">"Nieuwe gebeurtenis"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Nieuwe relatie"</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>
<string name="description_star" msgid="2605854427360036550">"favoriet"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 9d8da99..f58f81c 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -71,7 +71,7 @@
<string name="editContact_title_insert" msgid="9125600232291405757">"Nowy kontakt"</string>
<string name="label_phonetic_name" msgid="2288082649573927286">"Fonetycznie"</string>
<string name="label_notes" msgid="8337354953278341042">"Notatki"</string>
- <string name="label_sip_address" msgid="124073911714324974">"Dzwonienie przez internet"</string>
+ <string name="label_sip_address" msgid="124073911714324974">"Rozmowa internetowa"</string>
<string name="label_ringtone" msgid="8833166825330686244">"Dzwonek"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"Nazwisko (fonetycznie)"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Firma"</string>
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Domyślny"</string>
<string name="removePhoto" msgid="4898105274130284565">"Usuń zdjęcie"</string>
<string name="noContacts" msgid="8579310973261953559">"Brak kontaktów"</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Nie znaleziono pasujących kontaktów."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Brak kontaktów z numerami telefonów"</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Tylko kontakty z telefonami"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"Liczba kontaktów z numerem telefonu: 1"</item>
<item quantity="other" msgid="3299954047880968205">"Liczba kontaktów z numerami telefonów: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Brak widocznych kontaktów z numerami telefonów"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Brak kontaktów z numerami telefonów"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"Liczba kontaktów: 1"</item>
<item quantity="other" msgid="3578469907265375314">"Liczba kontaktów: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Brak widocznych kontaktów"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Brak kontaktów"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Brak widocznych kontaktów"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Brak kontaktów oznaczonych gwiazdką"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Brak kontaktów w grupie <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"Znaleziono: 1"</item>
<item quantity="other" msgid="3852668542926965042">"Znaleziono: <xliff:g id="COUNT">%d</xliff:g>"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"Znaleziono: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Kontakty"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Ulubione"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telefon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Rejestr"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Rejestr połączeń jest pusty."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Wyczyść rejestr połączeń"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Czy na pewno chcesz wyczyścić rejestr połączeń?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Czyszczenie dziennika połączeń"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"Numer MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Poczta głosowa"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"zdjęcie kontaktu"</string>
<string name="description_minus_button" msgid="387136707700230172">"minus"</string>
<string name="description_plus_button" msgid="515164827856229880">"plus"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Nośnik USB niedostępny"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Nośnik nie jest dostępny"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Brak karty SD"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Nie wykryto nośnika USB"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Nie wykryto nośnika"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Nie wykryto karty SD"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Wyszukiwanie danych vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Importuj z karty SIM"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Importuj z nośnika USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Importuj z nośnika"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Importuj z karty SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Eksportuj na nośnik USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Eksportuj na nośnik"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Eksportuj na kartę SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Udostępnij widoczne kontakty"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Importuj jeden plik vCard"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importuj wiele plików vCard"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Importuj wszystkie pliki vCard"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Wyszukiwanie danych vCard na nośniku USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Wyszukiwanie danych vCard na nośniku"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Wyszukiwanie danych vCard na karcie SD"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Skanowanie nośnika USB nie powiodło się"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Skanowanie nośnika nie powiodło się"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Skanowanie karty SD nie powiodło się"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Skanowanie nośnika USB nie powiodło się (przyczyna: „<xliff:g id="FAIL_REASON">%s</xliff:g>”)"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Skanowanie nośnika nie powiodło się (przyczyna: „<xliff:g id="FAIL_REASON">%s</xliff:g>”)"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Skanowanie karty SD nie powiodło się (przyczyna: „<xliff:g id="FAIL_REASON">%s</xliff:g>”)"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Błąd wejścia/wyjścia"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Niewystarczająca ilość pamięci (plik może być zbyt duży)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Nie można zanalizować pliku vCard z nieoczekiwanego powodu"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Ten format nie jest obsługiwany."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Nie można zaimportować karty vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"Na nośniku USB nie znaleziono żadnego pliku vCard"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Na nośniku nie znaleziono żadnego pliku vCard"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Na karcie SD nie znaleziono żadnego pliku vCard"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Nie można zebrać metainformacji z podanych plików vCard."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Nie można zaimportować co najmniej jednego pliku (%s)."</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Nie można wyeksportować danych kontaktu"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Nie można wyeksportować danych kontaktu."\n"Przyczyna niepowodzenia: „<xliff:g id="FAIL_REASON">%s</xliff:g>”."</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Brak kontaktów, które można wyeksportować"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Zbyt wiele plików vCard na nośniku USB"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Zbyt wiele plików vCard na nośniku"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Zbyt dużo plików vCard na karcie SD"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Wymagana nazwa pliku jest zbyt długa („<xliff:g id="FILENAME">%s</xliff:g>”)"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Zakończono eksportowanie pliku <xliff:g id="FILENAME">%s</xliff:g>"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Imię (fonetycznie)"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Drugie imię (fonetycznie)"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Nazwisko (fonetycznie)"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Nazwisko (fonetycznie)"</string>
<string name="account_type_format" msgid="718948015590343010">"Kontakt <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
- <string name="from_account_format" msgid="687567483928582084">"z <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Użyj tego zdjęcia"</string>
<string name="contact_read_only" msgid="1203216914575723978">"W tym urządzeniu nie można edytować informacji kontaktowych <xliff:g id="SOURCE">%1$s</xliff:g>."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Brak dodatkowych informacji dla tego kontaktu"</string>
@@ -433,6 +437,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"Nie wybrano kontaktów."</string>
<string name="add_field" msgid="2384260056674995230">"Dodaj inne pole"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Dodaj nowy nr telefonu"</string>
+ <string name="add_email" msgid="175079666329862215">"Dodaj nowy e-mail"</string>
+ <string name="add_im" msgid="5158094627521120439">"Dodaj nowe konto IM"</string>
+ <string name="add_address" msgid="418292312672970688">"Dodaj nowy adres"</string>
+ <string name="add_note" msgid="2753771325725383279">"Dodaj nową notatkę"</string>
+ <string name="add_website" msgid="4312391288948517344">"Dodaj nową witrynę"</string>
+ <string name="add_event" msgid="7488781591843886426">"Dodaj nowe wydarzenie"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Dodaj nową relację"</string>
<string name="contact_status_update_attribution" msgid="752179367353018597">"za pośrednictwem: <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>, za pośrednictwem: <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="description_star" msgid="2605854427360036550">"ulubione"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 18d59c2..91e33a9 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Predefinido"</string>
<string name="removePhoto" msgid="4898105274130284565">"Remover fotografia"</string>
<string name="noContacts" msgid="8579310973261953559">"Sem contactos."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Não foram encontrados contactos correspondentes."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Sem contactos com números de telefone."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Apenas contactos com telefones"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"1 contacto com número de telefone"</item>
<item quantity="other" msgid="3299954047880968205">"<xliff:g id="COUNT">%d</xliff:g> contactos com números de telefone"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Sem contactos visíveis com números de telefone"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Sem contactos com números de telefone"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 contacto"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> contactos"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Sem contactos visíveis"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Sem contactos"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Sem contactos visíveis"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Sem contactos marcados com uma estrela"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Sem contactos em <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"1 encontrado"</item>
<item quantity="other" msgid="3852668542926965042">"<xliff:g id="COUNT">%d</xliff:g> encontrado(s)"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> encontrado(s)"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Contactos"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoritos"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telefone"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Chamadas"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"O registo de chamadas está vazio."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Limpar registo de chamadas"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Tem a certeza de que pretende limpar o registo de chamadas?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Limpar registo de chamadas"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Correio de voz"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"fotografia do contacto"</string>
<string name="description_minus_button" msgid="387136707700230172">"menos"</string>
<string name="description_plus_button" msgid="515164827856229880">"mais"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Armaz. USB não disponível"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Armazen. indisponível"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Nenhum cartão SD"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Armaz. USB não detectado"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Não há armazenamento detectado"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Não foi detectado nenhum cartão SD"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"A procurar vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Importar do cartão SIM"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Importar do armaz. USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Importar do armazenamento"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Importar do cartão SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Exportar para armaz. USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Exportar para o armazen."</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Exportar para cartão SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Partilhar contactos visíveis"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Importar um ficheiro VCard"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importar vários ficheiros vCard"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Importar todos os ficheiros VCard"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"A pesquisar dados do vCard no armazenamento USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"A pesquisar dados do vCard no armazenamento"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Procurar dados do vCard no cartão SD"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Falha ao analisar armazenamento USB"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Falha ao digitalizar armazenamento"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Falha na análise do cartão SD"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Falha ao analisar armazenamento USB (Motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Falha ao analisar o armazenamento (Motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Falha na análise do cartão SD (Motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Erro de E/S"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"A memória não é suficiente (o ficheiro pode ser demasiado grande)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Falha na análise do vCard por motivo inesperado"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"O formato não é suportado."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Falha ao importar vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"Não foi encontrado nenhum ficheiro vCard no armazenamento USB"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Não foi encontrado nenhum ficheiro vCard no armazenamento"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Não foi encontrado nenhum ficheiro vCard no cartão SD"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"A recolha de meta informações de ficheiro(s) vCard específicado(s) falhou."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"A importação de um ou vários ficheiros falhou (%s)."</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Falha ao exportar dados de contacto"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Falha na exportação de dados de contacto."\n"Motivo da falha: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Não existe um contacto exportável"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Existem demasiados ficheiros vCard no armazenamento USB"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Existem demasiados ficheiros vCard no armazenamento"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Demasiados ficheiros vCard no cartão SD"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Nome de ficheiro demasiado longo (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"A exportação do <xliff:g id="FILENAME">%s</xliff:g> terminou"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Fonética do segundo nome"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Fonética do primeiro apelido"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Fonética do segundo apelido"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Nome fonético"</string>
<string name="account_type_format" msgid="718948015590343010">"Contacto de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
- <string name="from_account_format" msgid="687567483928582084">"de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Utilizar esta fotografia"</string>
<string name="contact_read_only" msgid="1203216914575723978">"Não é possível editar as informações de contacto do <xliff:g id="SOURCE">%1$s</xliff:g> neste dispositivo."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Não há informações adicionais para este contacto"</string>
@@ -433,6 +437,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"Nenhum contacto seleccionado."</string>
<string name="add_field" msgid="2384260056674995230">"Adicionar outro campo"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Adic. novo n.º telef."</string>
+ <string name="add_email" msgid="175079666329862215">"Adicionar novo e-mail"</string>
+ <string name="add_im" msgid="5158094627521120439">"Adic. nova conta MI"</string>
+ <string name="add_address" msgid="418292312672970688">"Adicionar novo endereço"</string>
+ <string name="add_note" msgid="2753771325725383279">"Adicionar nova nota"</string>
+ <string name="add_website" msgid="4312391288948517344">"Adicionar novo site"</string>
+ <string name="add_event" msgid="7488781591843886426">"Adicionar novo evento"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Adicionar nova relação"</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>
<string name="description_star" msgid="2605854427360036550">"favorito"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 0cd908f..dc1ea58 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Padrão"</string>
<string name="removePhoto" msgid="4898105274130284565">"Remover foto"</string>
<string name="noContacts" msgid="8579310973261953559">"Nenhum contato."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Nenhum contato correspondente foi encontrado."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Nenhum contato com números de telefone."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Apenas contatos com telefones"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"Um contato com número de telefone"</item>
<item quantity="other" msgid="3299954047880968205">"<xliff:g id="COUNT">%d</xliff:g> contatos com números de telefone"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Nenhum contato visível com números de telefone"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Nenhum contato com números de telefone"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 contato"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> contatos"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Não há contatos visíveis"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Nenhum contato"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Não há contatos visíveis"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Nenhum contato com estrela"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Nenhum contato em <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"Um encontrado"</item>
<item quantity="other" msgid="3852668542926965042">"<xliff:g id="COUNT">%d</xliff:g> encontrados"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> encontrados"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Contatos"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoritos"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telefone"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Chamadas"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"O registro de chamadas está vazio."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Limpar registro de chamadas"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Tem certeza de que deseja limpar o registro de chamadas?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Limpando registro de chamadas"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Correio de voz"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"foto do contato"</string>
<string name="description_minus_button" msgid="387136707700230172">"menos"</string>
<string name="description_plus_button" msgid="515164827856229880">"mais"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Armaz. USB não disponível"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Armazenamento não disponível"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Nenhum cartão SD"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Nenhum armaz. USB detectado"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Nenhum armazenamento detectado"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Nenhum cartão SD detectado"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Pesquisando vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Importar do cartão SIM"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Importar do armaz. USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Importar do armazenamento"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Importar do cartão SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Exportar para armaz. USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Exportar para o armazenamento"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Exportar para cartão SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Compartilhar contatos visíveis"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Importar um arquivo do vCard"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importar vários arquivos do vCard"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Importar todos os arquivos do vCard"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Procurando dados do vCard no armazenamento USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Procurando dados do vCard no armazenamento"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Procurando dados do vCard no cartão SD"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Falha na verificação do armazenamento USB"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Falha na verificação do armazenamento"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Falha na verificação do cartão SD"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Falha na verificação do armazenamento USB (Motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Falha na verificação do armazenamento (Motivo: <xliff:g id="FAIL_REASON">%s</xliff:g>)"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Falha na verificação do cartão SD (Motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Erro E/S"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Memória insuficiente (o arquivo talvez seja muito grande)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Falha ao analisar o vCard por razão inesperada"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"O formato não é suportado."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Falha ao importar vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"Nenhum arquivo de vCard encontrado no armazenamento USB"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Nenhum arquivo de vCard encontrado no armazenamento"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Nenhum arquivo de vCard encontrado no cartão SD"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Falha ao coletar metainformações dos arquivos de vCard fornecidos."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Falha na importação de um ou mais arquivos (%s)."</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Falha ao exportar dados do contato"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Falha ao exportar dados dos contatos."\n"Motivo da falha: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Não há contatos exportáveis"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Muitos arquivos do vCard no armazenamento USB"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Muitos arquivos de vCard no armazenamento"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Muitos arquivos do vCard no cartão SD"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"O nome de arquivo exigido é muito longo (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Exportação concluída <xliff:g id="FILENAME">%s</xliff:g>"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Nome fonético"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Nome do meio fonético"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Sobrenome fonético"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Nome fonético"</string>
<string name="account_type_format" msgid="718948015590343010">"Contato de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
- <string name="from_account_format" msgid="687567483928582084">"de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Usar esta foto"</string>
<string name="contact_read_only" msgid="1203216914575723978">"As informações de contato de <xliff:g id="SOURCE">%1$s</xliff:g> não podem ser editadas neste aparelho."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Não há informações adicionais para este contato"</string>
@@ -433,6 +437,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"Nenhum contato selecionado."</string>
<string name="add_field" msgid="2384260056674995230">"Adicionar outro campo"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Adicionar num. de tel."</string>
+ <string name="add_email" msgid="175079666329862215">"Adicionar novo e-mail"</string>
+ <string name="add_im" msgid="5158094627521120439">"Adic. conta de IM"</string>
+ <string name="add_address" msgid="418292312672970688">"Adicionar endereço"</string>
+ <string name="add_note" msgid="2753771325725383279">"Adicionar nota"</string>
+ <string name="add_website" msgid="4312391288948517344">"Adicionar novo site"</string>
+ <string name="add_event" msgid="7488781591843886426">"Adicionar evento"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Adicionar relac."</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>
<string name="description_star" msgid="2605854427360036550">"favorito"</string>
diff --git a/res/values-rm/strings.xml b/res/values-rm/strings.xml
index c2ea934..e558a89 100644
--- a/res/values-rm/strings.xml
+++ b/res/values-rm/strings.xml
@@ -101,6 +101,8 @@
<!-- no translation found for removePhoto (4898105274130284565) -->
<skip />
<string name="noContacts" msgid="8579310973261953559">"Nagins contacts"</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Betg chattà in contact correspundent."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Nagin contact dispona d\'in numer da telefon."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Mo contacts cun telefon"</string>
@@ -138,6 +140,8 @@
<item quantity="other" msgid="7988132539476575389">"Chattà <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Contacts"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favurits"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telefon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Cloms"</string>
@@ -153,6 +157,8 @@
<string name="recentCalls_empty" msgid="247053222448663107">"La glista da cloms e vida"</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Stizzar il protocol da cloms"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Vulais Vus propi stizzar il protocol da cloms?"</string>
+ <!-- no translation found for clearCallLogProgress_title (6870412675015656948) -->
+ <skip />
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Mailbox"</string>
@@ -212,25 +218,25 @@
<string name="description_contact_photo" msgid="3387458082667894062">"foto dal contact"</string>
<string name="description_minus_button" msgid="387136707700230172">"minus"</string>
<string name="description_plus_button" msgid="515164827856229880">"plus"</string>
- <!-- outdated translation 5911758680339949273 --> <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Nagina carta SD"</string>
+ <!-- outdated translation 5911758680339949273 --> <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Nagina carta SD"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Nagina carta SD"</string>
- <!-- outdated translation 6019391476490445358 --> <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Betg chattà ina carta SD."</string>
+ <!-- outdated translation 6019391476490445358 --> <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Betg chattà ina carta SD."</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Betg chattà ina carta SD."</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Tschertgar datas vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Importar da la carta SIM"</string>
- <!-- outdated translation 8550360976693202816 --> <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Importar da la carta SD"</string>
+ <!-- outdated translation 8550360976693202816 --> <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Importar da la carta SD"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Importar da la carta SD"</string>
- <!-- outdated translation 2597105442616166277 --> <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Exportar sin la carta SD"</string>
+ <!-- outdated translation 2597105442616166277 --> <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Exportar sin la carta SD"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Exportar sin la carta SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Cundivider ils contacts visibels"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Importar ina datoteca vCard"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importar pliras datotecas vCard"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Importar tut las datotecas vCard"</string>
- <!-- outdated translation 6917522333561434546 --> <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Tschertgar datas vCard sin la carta SD"</string>
+ <!-- outdated translation 6917522333561434546 --> <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Tschertgar datas vCard sin la carta SD"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Tschertgar datas vCard sin la carta SD"</string>
- <!-- outdated translation 3506782007953167180 --> <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Errur cun leger la carta SD"</string>
+ <!-- outdated translation 3506782007953167180 --> <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Errur cun leger la carta SD"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Errur cun leger la carta SD"</string>
- <!-- no translation found for scanning_sdcard_failed_message (5645544323676912703) -->
+ <!-- no translation found for scanning_sdcard_failed_message (4106156155205860626) -->
<skip />
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Errur cun leger la carta SD. Il motiv: «<xliff:g id="FAIL_REASON">%s</xliff:g>»"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Errur I/O"</string>
@@ -240,7 +246,7 @@
<skip />
<!-- no translation found for vcard_import_failed (7718330063493653085) -->
<skip />
- <!-- no translation found for import_failure_no_vcard_file (8809370398968655782) -->
+ <!-- no translation found for import_failure_no_vcard_file (6339234836196984924) -->
<skip />
<!-- no translation found for import_failure_no_vcard_file (1730986357514922756) -->
<skip />
@@ -276,7 +282,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Errur cun exportar las datas da contact"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Errur cun exportar las datas da contact. "\n"Il motiv: «<xliff:g id="FAIL_REASON">%s</xliff:g>»"</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Nagin contact exportabel"</string>
- <!-- outdated translation 7084146295639672658 --> <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"La carta SD cuntegna memia bleras datotecas vCard"</string>
+ <!-- outdated translation 7084146295639672658 --> <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"La carta SD cuntegna memia bleras datotecas vCard"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"La carta SD cuntegna memia bleras datotecas vCard"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Il num da datoteca necessari è memia lung («<xliff:g id="FILENAME">%s</xliff:g>»)"</string>
<!-- no translation found for exporting_vcard_finished_title (4259736138838583213) -->
@@ -425,8 +431,11 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Prenum fonetic"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Segund prenum fonetic"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Num da famiglia fonetic"</string>
+ <!-- no translation found for name_phonetic (4259595234312430484) -->
+ <skip />
<string name="account_type_format" msgid="718948015590343010">"Contact <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
- <string name="from_account_format" msgid="687567483928582084">"da <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Utilisar quest foto"</string>
<string name="contact_read_only" msgid="1203216914575723978">"Vus na pudais betg modifitgar las infurmaziuns dal contact <xliff:g id="SOURCE">%1$s</xliff:g> sin quest apparat."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Naginas infurmaziuns supplementaras per quest contact"</string>
@@ -467,6 +476,22 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"Betg tschernì in contact"</string>
<!-- outdated translation 5257149039253569615 --> <string name="add_field" msgid="2384260056674995230">"Agiuntar infurmaziuns"</string>
+ <!-- no translation found for add_phone (4421904942555210013) -->
+ <skip />
+ <!-- no translation found for add_email (175079666329862215) -->
+ <skip />
+ <!-- no translation found for add_im (5158094627521120439) -->
+ <skip />
+ <!-- no translation found for add_address (418292312672970688) -->
+ <skip />
+ <!-- no translation found for add_note (2753771325725383279) -->
+ <skip />
+ <!-- no translation found for add_website (4312391288948517344) -->
+ <skip />
+ <!-- no translation found for add_event (7488781591843886426) -->
+ <skip />
+ <!-- no translation found for add_relationship (3083762399737240006) -->
+ <skip />
<string name="contact_status_update_attribution" msgid="752179367353018597">"entras <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> entras <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="description_star" msgid="2605854427360036550">"favurit"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index c993273..5cabe0e 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Prestabilit"</string>
<string name="removePhoto" msgid="4898105274130284565">"Eliminaţi fotografia"</string>
<string name="noContacts" msgid="8579310973261953559">"Nicio persoană în agendă."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Nu a fost găsită nicio persoană potrivită în agendă."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Nicio persoană din agendă cu numere de telefon."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Numai persoanele din agendă cu numere de telefon"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"1 persoană din agendă cu număr de telefon"</item>
<item quantity="other" msgid="3299954047880968205">"<xliff:g id="COUNT">%d</xliff:g> (de) persoane din agendă cu numere de telefon"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Nicio persoană din agendă vizibilă cu numere de telefon"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Nicio persoană din agendă cu numere de telefon"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 persoană din Agendă"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> (de) persoane din Agendă"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Nicio persoană din agendă nu este vizibilă"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Nicio persoană în agendă"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Nicio persoană din agendă nu este vizibilă"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Nicio persoană din agendă marcată cu stea"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Nicio persoană din agendă în <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"A fost găsită 1 persoană din agendă"</item>
<item quantity="other" msgid="3852668542926965042">"Au fost găsite <xliff:g id="COUNT">%d</xliff:g> (de) persoane din agendă"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"Au fost găsite <xliff:g id="COUNT">%d</xliff:g> (de) persoane din agendă"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Agendă"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favorite"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telefon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Jurnal de apeluri"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Jurnalul de apeluri este gol."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Ştergeţi jurnalul de apeluri"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Sigur doriţi ştergerea jurnalului de apeluri?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Se goleşte jurnalul de apeluri"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Mesagerie vocală"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"fotografia persoanei din agendă"</string>
<string name="description_minus_button" msgid="387136707700230172">"minus"</string>
<string name="description_plus_button" msgid="515164827856229880">"plus"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Stoc. USB nu este disp."</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Stocare indisponibilă"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Niciun card SD"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Stocare USB nedetectată"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Nicio stocare detectată"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Niciun card SD detectat"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Se caută date în format vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Importaţi de pe cardul SIM"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Import. din stocarea USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Importaţi din stocare"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Importaţi de pe cardul SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Exportaţi în stocarea USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Exportaţi în stocare"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Exportaţi pe cardul SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Distribuiţi persoanele vizibile din agendă"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Importaţi un fişier vCard"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importaţi fişiere multiple vCard"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Importaţi toate fişierele vCard"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Se caută date vCard în spaţiul de stocare USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Se caută date vCard în spaţiul de stocare"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Se caută date vCard pe cardul SD"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Scanarea stocării USB a eşuat"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Scanarea stocării nu a reuşit"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Scanarea cardului SD a eşuat"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Scanarea stocării USB a eşuat (Motiv: „<xliff:g id="FAIL_REASON">%s</xliff:g>”)"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Scanarea stocării nu a reuşit (Motiv: „<xliff:g id="FAIL_REASON">%s</xliff:g>”)"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Scanarea cardului SD eşuată (Motiv: „<xliff:g id="FAIL_REASON">%s</xliff:g>”)"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Eroare I/E"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Memoria este insuficientă (probabil fişierul este prea mare)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Analiza vCard a eşuat dintr-un motiv necunoscut"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Formatul nu este acceptat."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Nu a reuşit să importe vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"Niciun fişier vCard găsit în stocarea USB"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Nu a fost găsit niciun fişier vCard în spaţiul de stocare"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Niciun fişier vCard găsit pe cardul SD"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Colectarea metainformaţiilor pentru fişierele vCard indicate a eşuat."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Unul sau mai multe fişiere nu s-au putut importa (%s)."</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Exportul datelor persoanei din agendă a eşuat"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Exportul datelor din agendă a eşuat."\n" Motivul erorii: „<xliff:g id="FAIL_REASON">%s</xliff:g>”"</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Nicio persoană în agendă exportabilă"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Prea multe fişiere vCard pe spaţiul de stocare USB"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Prea multe fişiere vCard în spaţiul de stocare"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Prea multe fişiere de tip vCard pe cardul SD"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Numele de fişier este prea lung („<xliff:g id="FILENAME">%s</xliff:g>”)"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"S-a finalizat exportul <xliff:g id="FILENAME">%s</xliff:g>"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Prenume fonetic"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Numele mijlociu fonetic"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Numele de familie fonetic"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Nume fonetic"</string>
<string name="account_type_format" msgid="718948015590343010">"Persoana din agendă din <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
- <string name="from_account_format" msgid="687567483928582084">"din <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Utilizaţi această fotografie"</string>
<string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g> Informaţiile despre această persoană din agendă nu se pot edita pe acest dispozitiv."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Nicio informaţie suplimentară pentru această persoană din agendă"</string>
@@ -423,13 +427,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Dezinstalaţi unele aplicaţii"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Încercaţi din nou trecerea la o versiune superioară"</string>
<string name="search_results_searching" msgid="7755623475227227314">"Se caută..."</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"Afişaţi elementele selectate"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"Afişaţi-le pe toate"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"Selectaţi-le pe toate"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"Deselectaţi-le pe toate"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"Nu aţi selectat nicio persoană din Agendă."</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"Afişaţi elementele selectate"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"Afişaţi-i pe toţi"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"Selectaţi-le pe toate"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"Deselectaţi-le pe toate"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"1 destinatar selectat"</item>
+ <item quantity="other" msgid="4608837420986126229">"<xliff:g id="COUNT">%d</xliff:g> (de) destinatari selectaţi"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"Nu aţi selectat nicio persoană din Agendă."</string>
<string name="add_field" msgid="2384260056674995230">"Adăugaţi alt câmp"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Adăugaţi nr. tel. nou"</string>
+ <string name="add_email" msgid="175079666329862215">"Adăugaţi e-mail nou"</string>
+ <string name="add_im" msgid="5158094627521120439">"Adăugaţi cont IM nou"</string>
+ <string name="add_address" msgid="418292312672970688">"Adăugaţi adresă nouă"</string>
+ <string name="add_note" msgid="2753771325725383279">"Adăugaţi notă nouă"</string>
+ <string name="add_website" msgid="4312391288948517344">"Adăugaţi site web nou"</string>
+ <string name="add_event" msgid="7488781591843886426">"Adăugaţi eveniment nou"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Adăugaţi relaţie nouă"</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>
<string name="description_star" msgid="2605854427360036550">"preferate"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 2495b10..690207b 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -23,7 +23,7 @@
<string name="shortcutDialContact" msgid="746622101599186779">"Быстрый звонок"</string>
<string name="shortcutMessageContact" msgid="2460337253595976198">"Быстрое сообщение"</string>
<string name="shortcutActivityTitle" msgid="6642877210643565436">"Выбрать контакт для быстрого вызова"</string>
- <string name="callShortcutActivityTitle" msgid="6065749861423648991">"Выбрать номер для вызова"</string>
+ <string name="callShortcutActivityTitle" msgid="6065749861423648991">"Выберите номер для вызова"</string>
<string name="messageShortcutActivityTitle" msgid="3084542316620335911">"Выбрать номер для отправки сообщения"</string>
<string name="contactPickerActivityTitle" msgid="6886592363525235031">"Выбор контакта"</string>
<string name="starredList" msgid="4817256136413959463">"Помеченные"</string>
@@ -73,7 +73,7 @@
<string name="label_notes" msgid="8337354953278341042">"Примечания"</string>
<string name="label_sip_address" msgid="124073911714324974">"Интернет-вызов"</string>
<string name="label_ringtone" msgid="8833166825330686244">"Мелодия"</string>
- <string name="ghostData_phonetic_name" msgid="7852749081984070902">"Произношение имени"</string>
+ <string name="ghostData_phonetic_name" msgid="7852749081984070902">"Транскрипция имени"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Компания"</string>
<string name="ghostData_title" msgid="7496735200318496110">"Название"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"Контакт не существует."</string>
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"По умолчанию"</string>
<string name="removePhoto" msgid="4898105274130284565">"Удалить фото"</string>
<string name="noContacts" msgid="8579310973261953559">"Нет контактов."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Подходящие контакты не найдены."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Нет контактов с номерами телефонов."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Контакты с телефонами"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"Контакты с номерами телефона: 1"</item>
<item quantity="other" msgid="3299954047880968205">"Контакты с номерами телефонов: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Нет видимых контактов с номерами телефонов"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Нет контактов с номерами телефонов"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"Контактов: 1"</item>
<item quantity="other" msgid="3578469907265375314">"Контактов: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Видимые контакты отсутствуют."</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Нет контактов"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Нет видимых контактов"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Нет помеченных контактов"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Нет контактов в: <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"Найдено: 1"</item>
<item quantity="other" msgid="3852668542926965042">"Найдено: <xliff:g id="COUNT">%d</xliff:g>"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"Найдено: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Контакты"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Избранное"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Кнопки"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Вызовы"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Список вызовов пуст."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Очистить список вызовов"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Действительно очистить список вызовов?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Очистка списка вызовов"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Голосовая почта"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"фотография контакта"</string>
<string name="description_minus_button" msgid="387136707700230172">"минус"</string>
<string name="description_plus_button" msgid="515164827856229880">"плюс"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"USB-накопитель недоступен"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Накопитель недоступен"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Нет SD-карты"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"USB-накопитель не найден"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Накопитель не найден"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"SD-карта не обнаружена"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Поиск vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Импортировать с SIM-карты"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Импорт с USB-накопителя"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Импорт из накопителя"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Импортировать с SD-карты"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Экспорт на USB-накопитель"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Экспорт на накопитель"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Экспортировать на SD-карту"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Передать видимые контакты"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Импорт одного файла VCard"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Импорт нескольких файлов vCard"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Импорт всех файлов VCard"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Поиск данных vCard на USB-накопителе"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Поиск данных vCard на накопителе..."</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Поиск данных vCard на SD-карте"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Не удалось просканировать USB-накопитель"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Не удалось просканировать накопитель"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Не удалось сканировать SD-карту."</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Не удалось просканировать USB-накопитель (<xliff:g id="FAIL_REASON">%s</xliff:g>)"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Не удалось просканировать накопитель (<xliff:g id="FAIL_REASON">%s</xliff:g>)"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Не удалось просканировать SD-карту (причина: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Ошибка ввода-вывода"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Недостаточно памяти (возможно, файл слишком велик)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Не удалось обработать vCard по неизвестной причине."</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Формат не поддерживается."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Не удалось импортировать vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"На USB-накопителе отсутствуют файлы vCard"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"На накопителе нет vCard-файлов"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"На SD-карте не найдены файлы VCard"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Не удалось собрать метаинформацию файлов VCard."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Не удалось импортировать один или несколько файлов (%s)."</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Не удалось экспортировать данные контакта."</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Не удалось экспортировать данные контакта."\n"Причина: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Нет контактов, которые можно экспортировать."</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Слишком много файлов vCard на USB-накопителе"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Слишком много vCard-файлов на накопителе"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Слишком много файлов VCard на SD-карте."</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Название файла слишком длинное (<xliff:g id="FILENAME">%s</xliff:g>)."</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Экспорт <xliff:g id="FILENAME">%s</xliff:g> завершен"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Имя (транскрипция)"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Отчество (транскрипция)"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Фамилия (транскрипция)"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Транскрипция имени"</string>
<string name="account_type_format" msgid="718948015590343010">"Контакт <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
- <string name="from_account_format" msgid="687567483928582084">"из <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Использовать эту фотографию"</string>
<string name="contact_read_only" msgid="1203216914575723978">"Невозможно изменить контактную информацию <xliff:g id="SOURCE">%1$s</xliff:g> на этом устройстве."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Отсутствует дополнительная информация об этом контакте."</string>
@@ -433,6 +437,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"Контакты не выбраны."</string>
<string name="add_field" msgid="2384260056674995230">"Добавить другое поле"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Добавить тел. номер"</string>
+ <string name="add_email" msgid="175079666329862215">"Добавить эл. почту"</string>
+ <string name="add_im" msgid="5158094627521120439">"Добавить чат"</string>
+ <string name="add_address" msgid="418292312672970688">"Добавить адрес"</string>
+ <string name="add_note" msgid="2753771325725383279">"Добавить примечание"</string>
+ <string name="add_website" msgid="4312391288948517344">"Добавить веб-сайт"</string>
+ <string name="add_event" msgid="7488781591843886426">"Добавить событие"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Добавить отношение"</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>
<string name="description_star" msgid="2605854427360036550">"избранное"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index b3a0385..59cc4e7 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Predvolené"</string>
<string name="removePhoto" msgid="4898105274130284565">"Odstrániť fotografiu"</string>
<string name="noContacts" msgid="8579310973261953559">"Žiadne kontakty."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Nenašli sa žiadne zodpovedajúce kontakty."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Ku kontaktom nie sú priradené žiadne telefónne čísla."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Iba kontakty s telefónmi"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"1 kontakt s telefónnym číslom"</item>
<item quantity="other" msgid="3299954047880968205">"Počet kontaktov s telefónnymi číslami: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Žiadne kontakty s telefónnymi číslami nie sú viditeľné"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Ku kontaktom nie sú priradené žiadne telefónne čísla"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"Počet kontaktov: 1"</item>
<item quantity="other" msgid="3578469907265375314">"Počet kontaktov: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Žiadne kontakty nie sú viditeľné"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Žiadne kontakty"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Žiadne kontakty nie sú viditeľné"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Žiadne kontakty označené hviezdičkou"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Žiadne kontakty v položke <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"Počet nájdených položiek: 1"</item>
<item quantity="other" msgid="3852668542926965042">"Počet nájdených položiek: <xliff:g id="COUNT">%d</xliff:g>"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"Počet nájdených položiek: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Kontakty"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Obľúbené"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telefón"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Denník hovorov"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Záznam hovorov je prázdny."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Vymazať záznam hovorov"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Naozaj chcete odstrániť denník hovorov?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Vymazávanie denníka hovorov"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Hlasová schránka"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"fotografia kontaktu"</string>
<string name="description_minus_button" msgid="387136707700230172">"mínus"</string>
<string name="description_plus_button" msgid="515164827856229880">"plus"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Ukl. priestor USB nedostup."</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Uklad. pr. je nedostupný"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Žiadna karta SD"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Nebol rozpoznaný ukl. priestor USB"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Ukladací priestor sa nenašiel"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Nebola zistená žiadna karta SD"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Vyhľadávanie karty vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Importovať z karty SIM"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Import z ukl. priestoru USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Import z ukl. priestoru"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Importovať z karty SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Export do ukl. priestoru USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Export do uklad. priest."</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Exportovať na kartu SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Zdieľať viditeľné kontakty"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Importovať jeden súbor vCard"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importovať niekoľko súborov vCard"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Importovať všetky súbory vCard"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Vyhľadávanie údajov karty vCard v ukladacom priestore USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Vyhľadávanie údajov karty vCard v ukladacom priestore"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Prebieha hľadanie údajov karty vCard na karte SD"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Vyhľadávanie v ukladacom priestore USB zlyhalo"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Skenovanie ukladacieho priestoru zlyhalo"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Vyhľadávanie na karte SD zlyhalo"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Vyhľadávanie v ukladacom priestore USB zlyhalo (Dôvod: „<xliff:g id="FAIL_REASON">%s</xliff:g>“)"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Vyhľadávanie v ukladacom priestore zlyhalo (Dôvod: „<xliff:g id="FAIL_REASON">%s</xliff:g>“)"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Vyhľadávanie na karte SD zlyhalo. (Dôvod: <xliff:g id="FAIL_REASON">%s</xliff:g>)"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Chyba I/O"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Nie je k dispozícii dostatok pamäte (súbor môže byť príliš veľký)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Analýza karty vCard z neznámeho dôvodu zlyhala."</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Formát nie je podporovaný."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Importovanie vizitky vCard zlyhalo"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"V ukladacom priestore USB nebola nájdená žiadna karta vCard"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"V ukladacom priestore sa nenašiel žiadny súbor vCard"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Na karte SD nebol nájdený žiadny súbor vCard"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Zhromaždenie metainformácií zadaných súborov vCard zlyhalo."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Import jedného alebo viacerých súborov zlyhal (%s)."</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Export údajov kontaktov zlyhal"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Export údajov kontaktov zlyhal."\n"Príčina chyby: <xliff:g id="FAIL_REASON">%s</xliff:g>"</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Nedá sa exportovať nijaký kontakt"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"V ukladacom priestore USB je príliš veľa súborov vCard"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"V ukladacom priestore je príliš veľa súborov vCard"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Na karte SD sa nachádza príliš veľa súborov vCard"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Požadovaný názov súboru (<xliff:g id="FILENAME">%s</xliff:g>) je príliš dlhý"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Export vizitky <xliff:g id="FILENAME">%s</xliff:g> bol dokončený"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Krstné meno (foneticky)"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Druhé meno (foneticky)"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Priezvisko (foneticky)"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Meno (foneticky)"</string>
<string name="account_type_format" msgid="718948015590343010">"Kontakt <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
- <string name="from_account_format" msgid="687567483928582084">"z miesta: <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Použiť túto fotografiu"</string>
<string name="contact_read_only" msgid="1203216914575723978">"Kontaktné informácie zo zdroja <xliff:g id="SOURCE">%1$s</xliff:g> nie je možné na tomto zariadení upraviť."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Pri tomto kontakte nie sú uvedené ďalšie informácie"</string>
@@ -423,13 +427,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Odinštalovať niektoré aplikácie"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Skúsiť inovovať znova"</string>
<string name="search_results_searching" msgid="7755623475227227314">"Prebieha vyhľadávanie..."</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"Zobraziť vybraté"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"Zobraziť všetky"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"Vybrať všetko"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"Zrušiť výber všetkých"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"Nie sú vybraté žiadne kontakty."</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"Zobraziť vybraté"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"Zobraziť všetky"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"Vybrať všetko"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"Zrušiť výber všetkých"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"Bol vybratý 1 príjemca"</item>
+ <item quantity="other" msgid="4608837420986126229">"Počet vybratých príjemcov: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"Nie sú vybraté žiadne kontakty."</string>
<string name="add_field" msgid="2384260056674995230">"Pridať ďalšie pole"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Pridať nové tel. číslo"</string>
+ <string name="add_email" msgid="175079666329862215">"Pridať nový e-mail"</string>
+ <string name="add_im" msgid="5158094627521120439">"Pridať nový účet IM"</string>
+ <string name="add_address" msgid="418292312672970688">"Pridať novú adresu"</string>
+ <string name="add_note" msgid="2753771325725383279">"Pridať novú poznámku"</string>
+ <string name="add_website" msgid="4312391288948517344">"Pridať novú lokalitu"</string>
+ <string name="add_event" msgid="7488781591843886426">"Pridať novú udalosť"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Pridať nový vzťah"</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>
<string name="description_star" msgid="2605854427360036550">"zaradiť medzi obľúbené"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 4f00e3c..5f4a480 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Privzeto"</string>
<string name="removePhoto" msgid="4898105274130284565">"Odstrani fotografijo"</string>
<string name="noContacts" msgid="8579310973261953559">"Ni stikov."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Najti ni bilo mogoče nobenega ustreznega stika."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Ni stikov s telefonskimi številkami."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Samo stiki s telefoni"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"1 stik s telefonsko število."</item>
<item quantity="other" msgid="3299954047880968205">"<xliff:g id="COUNT">%d</xliff:g> stikov s telefonskimi številkami"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Ni vidnih stikov s telefonskimi številkami"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Ni stikov s telefonskimi številkami"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 stik"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> stikov"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Ni vidnih stikov"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Ni stikov"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Ni vidnih stikov"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Ni stikov z zvezdico"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Ni stikov v: <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"1 najden"</item>
<item quantity="other" msgid="3852668542926965042">"<xliff:g id="COUNT">%d</xliff:g> najdenih"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> najdenih"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Stiki"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Priljubljeno"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telefon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Dnevnik klicev"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Dnevnik klicev je prazen."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Počisti dnevnik klicev"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Ali ste prepričani, da želite počistiti dnevnik klicev?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Brisanje dnevnika klicev"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Glasovna pošta"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"fotografija stika"</string>
<string name="description_minus_button" msgid="387136707700230172">"minus"</string>
<string name="description_plus_button" msgid="515164827856229880">"plus"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Pomnilnik USB ni na voljo"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Pomnilnik ni na voljo"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Ni kartice SD"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Pomnilnik USB ni zaznan"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Ni pomnilnika"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Kartica SD ni bila zaznana"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Iskanje vizitke vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Uvozi s kartice SIM"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Uvozi iz pomnilnika USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Uvoz iz pomnilnika"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Uvozi s kartice SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Izvozi v pomnilnik USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Izvoz v pomnilnik"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Izvozi na kartico SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Vidne stike deli z drugimi"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Uvozi eno datoteko z vizitko vCard"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Uvozi več datotek z vizitko vCard"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Uvozi vse datoteke vCard"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Iskanje podatkov vCard v pomnilniku USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Iskanje podatkov vCard v pomnilniku"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Iskanje podatkov vCard na kartici SD"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Pregledovanje pomnilnika USB ni uspelo"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Pregled pomnilnika ni uspel"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Pregledovanje kartice SD ni bilo uspešno"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Pregledovanje pomnilnika USB ni uspelo (Vzrok: »<xliff:g id="FAIL_REASON">%s</xliff:g>«)"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Pregled pomnilnika ni uspel (Vzrok: »<xliff:g id="FAIL_REASON">%s</xliff:g>«)"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Pregledovanje kartice SD ni bilo uspešno (Razlog: »<xliff:g id="FAIL_REASON">%s</xliff:g>«)"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Vhodno/izhodna napaka"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Ni dovolj pomnilnika (morda je datoteka prevelika)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Iz neznanega razloga razčlenjevanje vizitke vCard ni bilo uspešno"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Oblika zapisa ni podprta."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Uvoz kartice vCard ni uspel"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"Na disku USB ni datotek vCard"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"V pomnilniku ni datotek vCard"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Na kartici SD ni datotek vCard"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Metapodatkov datotek(e) vCard ni bilo mogoče zbrati."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Ene ali več datotek ni bilo mogoče uvoziti (%s)."</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Podatkov o stiku ni bilo mogoče izvoziti"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Izvoz podatkov o stiku ni bil uspešen."\n"Razlog: »<xliff:g id="FAIL_REASON">%s</xliff:g>«"</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Ni stikov za izvoz"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Preveč datotek vCard v pomnilniku USB"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"V pomnilniku je preveč datotek vCard"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Preveč datotek vCard na kartici SD"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Zahtevano ime datoteke je predolgo (<xliff:g id="FILENAME">%s</xliff:g>)"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Končan izvoz datoteke <xliff:g id="FILENAME">%s</xliff:g>"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Ime – fonetično"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Drugo ime – fonetično"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Priimek – fonetično"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Ime – fonetično"</string>
<string name="account_type_format" msgid="718948015590343010">"Stik <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
- <string name="from_account_format" msgid="687567483928582084">"od <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Uporabi to fotografijo"</string>
<string name="contact_read_only" msgid="1203216914575723978">"Podatkov o stiku <xliff:g id="SOURCE">%1$s</xliff:g> s to napravo ni mogoče urejati."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Ni dodatnih informacij za ta stik"</string>
@@ -423,13 +427,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Odstranite nekaj aplikacij"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Znova poskusi nadgraditi"</string>
<string name="search_results_searching" msgid="7755623475227227314">"Iskanje ..."</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"Pokaži izbrane"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"Pokaži vse"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"Izberi vse"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"Prekliči izbor vseh"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"Izbran ni noben stik."</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"Pokaži izbrane"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"Pokaži vse"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"Izberi vse"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"Prekliči izbor vseh"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"Izbran je 1 prejemnik"</item>
+ <item quantity="other" msgid="4608837420986126229">"Št. izbranih prejemnikov: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"Izbran ni noben stik."</string>
<string name="add_field" msgid="2384260056674995230">"Dodaj drugo polje"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Dodaj novo telefonsko številko"</string>
+ <string name="add_email" msgid="175079666329862215">"Dodaj novo e-pošto"</string>
+ <string name="add_im" msgid="5158094627521120439">"Dodaj nov račun za NS"</string>
+ <string name="add_address" msgid="418292312672970688">"Dodaj nov naslov"</string>
+ <string name="add_note" msgid="2753771325725383279">"Dodaj novo opombo"</string>
+ <string name="add_website" msgid="4312391288948517344">"Dodaj novo spletno mesto"</string>
+ <string name="add_event" msgid="7488781591843886426">"Dodaj nov dogodek"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Dodaj novo razmerje"</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>
<string name="description_star" msgid="2605854427360036550">"priljubljeno"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 332b1af..2cd8648 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Подразумевано"</string>
<string name="removePhoto" msgid="4898105274130284565">"Уклони фотографију"</string>
<string name="noContacts" msgid="8579310973261953559">"Нема контаката."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Није пронађен ниједан одговарајући контакт."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Нема контаката за које су унети бројеви телефона."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Само контакти за које су унети бројеви телефона"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"1 контакт са бројем телефона"</item>
<item quantity="other" msgid="3299954047880968205">"Бр. контаката са бројевима телефона: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Нема видљивих контаката за које су унети бројеви телефона."</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Нема контаката са бројевима телефона"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 контакт"</item>
<item quantity="other" msgid="3578469907265375314">"Kонтаката: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Нема видљивих контаката"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Нема контаката"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Нема видљивих контаката"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Нема контаката са звездицом"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Нема контаката у групи <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"1 пронађен"</item>
<item quantity="other" msgid="3852668542926965042">"<xliff:g id="COUNT">%d</xliff:g> пронађено"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> пронађено"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Контакти"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Омиљено"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Телефон"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Евиденција позива"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Евиденција позива је празна."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Обриши евиденцију позива"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Желите ли заиста да обришете евиденцију позива?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Брисање евиденције позива"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Говорна пошта"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"фотографија контакта"</string>
<string name="description_minus_button" msgid="387136707700230172">"минус"</string>
<string name="description_plus_button" msgid="515164827856229880">"плус"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"USB меморија је недоступна"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Меморија је недоступна"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Нема SD картице"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Није откривена USB меморија"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Није откривена меморија"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Није изабрана ниједна SD картица"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Претрага дигиталне визиткарте"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Увези са SIM картице"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Увоз из USB меморије"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Увези из меморије"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Увези са SD картице"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Извези у USB меморију"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Извези у меморију"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Извези на SD картицу"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Дели видљиве контакте"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Увези једну датотеку дигиталне визиткарте"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Увези више датотека дигиталних визиткарата"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Увези све датотеке дигиталних визиткарата"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Тражење података дигиталне визиткарте у USB меморији"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Тражење vCard података у меморији"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"У току је претрага података о дигиталним визиткартама на SD картици"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Неуспешно скенирање USB меморије"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Скенирање меморије није успело"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Скенирање SD картице није успело"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Неуспешно скенирање USB меморије (Разлог: „<xliff:g id="FAIL_REASON">%s</xliff:g>“)"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Скенирање меморије није успело (разлог: „<xliff:g id="FAIL_REASON">%s</xliff:g>“)"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Скенирање SD картице није успело (разлог: „<xliff:g id="FAIL_REASON">%s</xliff:g>“)"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"I/O грешка"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Нема довољно меморије (датотека је можда превелика)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Рашчлањивање дигиталне визиткарте није успело из неочекиваног разлога"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Формат није подржан."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Увоз vCard датотеке није успео"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"У USB меморији није пронађена ниједна vCard датотека"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"У меморији није пронађена ниједна vCard датотека"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"На SD картици није пронађена ниједна vCard датотека"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Неуспешно прикупљање мета података за дате датотеке дигиталне визиткарте."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Увоз неких датотека није успео (%s)."</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Извоз података о контактима није успео"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Извоз података о контактима није успео."\n"Разлог неуспеха: „<xliff:g id="FAIL_REASON">%s</xliff:g>“"</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Нема контаката за извоз"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Превише датотека дигиталне визиткарте у USB меморији"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Превише је vCard датотека у меморији"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"SD картица садржи превише датотека дигиталних визиткарата"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Захтевани назив датотеке је предугачак („<xliff:g id="FILENAME">%s</xliff:g>“)"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Извоз датотеке <xliff:g id="FILENAME">%s</xliff:g> је завршен"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Име – фонетски"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Средње име – фонетски"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Презиме – фонетски"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Име – фонетски"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> контакт"</string>
- <string name="from_account_format" msgid="687567483928582084">"са <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Користи ову фотографију"</string>
<string name="contact_read_only" msgid="1203216914575723978">"На овом уређају није могуће изменити информације о контакту <xliff:g id="SOURCE">%1$s</xliff:g>."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Нема додатних информације за овај контакт"</string>
@@ -423,13 +427,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Деинсталирајте неке апликације"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Поново покушај надоградњу"</string>
<string name="search_results_searching" msgid="7755623475227227314">"Претраживање..."</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"Прикажи изабрано"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"Прикажи све"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"Изабери све"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"Поништи све изборе"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"Није изабран ниједан контакт."</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"Прикажи изабрано"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"Прикажи све"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"Изабери све"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"Поништи све изборе"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"Изабран је 1 прималац"</item>
+ <item quantity="other" msgid="4608837420986126229">"Изабрано прималаца: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"Није изабран ниједан контакт."</string>
<string name="add_field" msgid="2384260056674995230">"Додај друго поље"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Додајте нови телефон"</string>
+ <string name="add_email" msgid="175079666329862215">"Додајте нову адресу"</string>
+ <string name="add_im" msgid="5158094627521120439">"Додајте нови IM налoг"</string>
+ <string name="add_address" msgid="418292312672970688">"Додајте нову адресу"</string>
+ <string name="add_note" msgid="2753771325725383279">"Додајте нову белешку"</string>
+ <string name="add_website" msgid="4312391288948517344">"Додајте нови веб сајт"</string>
+ <string name="add_event" msgid="7488781591843886426">"Додајте нови догађај"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Додајте нову везу"</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>
<string name="description_star" msgid="2605854427360036550">"омиљено"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index a87ec67..9483563 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Standardinställning"</string>
<string name="removePhoto" msgid="4898105274130284565">"Ta bort foto"</string>
<string name="noContacts" msgid="8579310973261953559">"Inga kontakter."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Inga matchande kontakter hittades."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Inga kontakter med telefonnummer."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Bara kontakter med telefoner"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"en kontakt med telefonnummer"</item>
<item quantity="other" msgid="3299954047880968205">"<xliff:g id="COUNT">%d</xliff:g> kontakter med telefonnummer"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Inga synliga kontakter med telefonnummer"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Inga kontakter med telefonnummer"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 kontakt"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> kontakter"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Det finns inga synliga kontakter"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Inga kontakter"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Det finns inga synliga kontakter"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Inga stjärnmärkta kontakter"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Inga kontakter i <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"1 hittades"</item>
<item quantity="other" msgid="3852668542926965042">"<xliff:g id="COUNT">%d</xliff:g> hittades"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> hittades"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Kontakter"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoriter"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telefon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Samtalshistorik"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Samtalshistoriken är tom."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Rensa samtalshistorik"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Vill du rensa samtalshistoriken?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Rensar samtalshistorik"</string>
<string name="imei" msgid="3045126336951684285">"IMEI-kod"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Röstbrevlåda"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"kontaktbild"</string>
<string name="description_minus_button" msgid="387136707700230172">"minus"</string>
<string name="description_plus_button" msgid="515164827856229880">"plus"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"USB-enhet ej tillgänglig"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Lagring otillgänglig"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Inget SD-kort"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Ingen USB-enhet hittades"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Ingen lagringsenhet hittades"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Inget SD-kort hittades"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Söker efter vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Importera från SIM-kort"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Importera från USB-enhet"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Importera från lagring"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Importera från SD-kort"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Exportera till USB-enhet"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Exportera till lagring"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Exportera till SD-kort"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Dela synliga kontakter"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Importera en vCard-fil"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importera flera vCard-filer"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Importera alla vCard-filer"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Söker efter vCard-data på USB-lagringsenhet"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Sökning efter vCard-data på lagringsenheten pågår"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Söker efter vCard-data på SD-kort"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Det gick inte att söka igenom USB-lagringsenheten"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Det gick inte att söka igenom lagringsenheten"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Det gick inte att läsa SD-kort"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Det gick inte att söka igenom USB-lagringsenheten (orsak: <xliff:g id="FAIL_REASON">%s</xliff:g>)"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Det gick inte att söka igenom lagringsenheten (orsak: <xliff:g id="FAIL_REASON">%s</xliff:g>)"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Det gick inte att skanna SD-kortet (orsak: <xliff:g id="FAIL_REASON">%s</xliff:g>)"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"I/O-fel"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Det finns för lite minne (filen kan vara för stor)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Det gick inte att analysera vCard av okänd anledning"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Formatet stöds inte."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Det gick inte att importera vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"Det finns ingen vCard-fil på USB-lagringsenheten"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Det finns ingen vCard-fil på lagringsenheten"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Det finns ingen vCard-fil på SD-kortet"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Det går inte att samla in metainformation för den eller de givna vCard-filerna."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"En eller flera filer kunde inte importeras: (%s)."</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Det gick inte att exportera kontaktdata"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Det gick inte att exportera kontaktdata."\n"Orsak: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Det finns ingen kontakt som kan exporteras"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"För många vCard-filer på USB-lagringsenheten"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"För många vCard-filer på lagringsenheten"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"För många vCard-filer på SD-kortet"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Det obligatoriska filnamnet är för långt (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"<xliff:g id="FILENAME">%s</xliff:g> har exporterats"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Fonetiskt förnamn"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetiskt mellannamn"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Fonetiskt efternamn"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Fonetiskt namn"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g>-kontakt"</string>
- <string name="from_account_format" msgid="687567483928582084">"från <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Använd det här fotot"</string>
<string name="contact_read_only" msgid="1203216914575723978">"Kontaktinformation för <xliff:g id="SOURCE">%1$s</xliff:g> kan inte redigeras i den här enheten."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Det finns ingen mer information för kontakten"</string>
@@ -420,7 +424,7 @@
<string name="locale_change_in_progress" msgid="7583992153091537467">"Kontaktlistan uppdateras så att språkändringen visas."</string>
<string name="upgrade_in_progress" msgid="474511436863451061">"Kontaktlistan uppdateras."</string>
<string name="upgrade_out_of_memory" msgid="6153384328042175667">"Kontakter håller på att uppgraderas. "\n\n"Uppgraderingsprocessen kräver ungefär <xliff:g id="SIZE_IN_MEGABYTES">%s</xliff:g> MB internt lagringsutrymme."\n\n"Välj ett av följande alternativ:"</string>
- <string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Avinstallera några program"</string>
+ <string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Avinstallera några appar"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Försök uppgradera igen"</string>
<string name="search_results_searching" msgid="7755623475227227314">"Söker..."</string>
<string name="menu_display_selected" msgid="6470001164297969034">"Visa markerade"</string>
@@ -433,6 +437,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"Inga kontakter har markerats."</string>
<string name="add_field" msgid="2384260056674995230">"Lägg till ett fält"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Lägg till nytt nummer"</string>
+ <string name="add_email" msgid="175079666329862215">"Lägg till ny e-post"</string>
+ <string name="add_im" msgid="5158094627521120439">"Lägg till IM-konto"</string>
+ <string name="add_address" msgid="418292312672970688">"Lägg till ny adress"</string>
+ <string name="add_note" msgid="2753771325725383279">"Lägg till kommentar"</string>
+ <string name="add_website" msgid="4312391288948517344">"Lägg till ny webbplats"</string>
+ <string name="add_event" msgid="7488781591843886426">"Lägg till ny aktivitet"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Lägg till ny relation"</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>
<string name="description_star" msgid="2605854427360036550">"favorit"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 4b4d52f..b7407b4 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"เริ่มต้น"</string>
<string name="removePhoto" msgid="4898105274130284565">"นำภาพออก"</string>
<string name="noContacts" msgid="8579310973261953559">"ไม่มีรายชื่อ"</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"ไม่พบรายชื่อที่ตรงกัน"</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"ไม่รายชื่อที่มีหมายเลขโทรศัพท์"</string>
<string name="showFilterPhones" msgid="4184858075465653970">"เฉพาะรายชื่อที่มีหมายเลขโทรศัพท์"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"1 รายชื่อติดต่อที่มีหมายเลขโทรศัพท์"</item>
<item quantity="other" msgid="3299954047880968205">"<xliff:g id="COUNT">%d</xliff:g> รายชื่อติดต่อที่มีหมายเลขโทรศัพท์"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"ไม่มีรายชื่อติดต่อที่แสดงซึ่งมีหมายเลขโทรศัพท์"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"ไม่มีรายชื่อติดต่อที่มีหมายเลขโทรศัพท์"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 รายชื่อติดต่อ"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> รายชื่อติดต่อ"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"ไม่มีรายชื่อที่แสดงไว้"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"ไม่มีรายชื่อติดต่อ"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"ไม่มีรายชื่อติดต่อที่แสดงไว้"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"ไม่มีรายชื่อที่ติดดาว"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"ไม่มีรายชื่อติดต่อใน <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"พบ 1 รายการ"</item>
<item quantity="other" msgid="3852668542926965042">"พบ <xliff:g id="COUNT">%d</xliff:g> รายการ"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"พบ <xliff:g id="COUNT">%d</xliff:g> รายการ"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"รายชื่อ"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"รายการโปรด"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"โทรศัพท์"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"บันทึกการโทร"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"บันทึกการโทรว่างเปล่า"</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"ล้างบันทึกการโทร"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"คุณแน่ใจหรือไม่ว่าต้องการล้างบันทึกการโทรทั้งหมด"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"การล้างบันทึกการโทร"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"ข้อความเสียง"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"ภาพของรายชื่อ"</string>
<string name="description_minus_button" msgid="387136707700230172">"minus"</string>
<string name="description_plus_button" msgid="515164827856229880">"plus"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"ที่เก็บข้อมูล USB ใช้งานไม่ได้"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"ไม่มีที่เก็บข้อมูล"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"ไม่มีการ์ด SD"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"ไม่พบที่เก็บข้อมูล USB"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"ไม่พบที่เก็บข้อมูล"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"ไม่พบการ์ด SD"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"กำลังค้นหา vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"นำเข้าจากซิมการ์ด"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"นำเข้าจากที่เก็บข้อมูล USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"นำเข้าจากที่เก็บข้อมูล"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"นำเข้าจากการ์ด SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"ส่งออกไปยังที่เก็บข้อมูล USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"ส่งออกไปยังที่เก็บข้อมูล"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"ส่งออกไปยังการ์ด SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"แบ่งปันสมุดโทรศัพท์ที่มองเห็น"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"นำเข้าไฟล์ vCard หนึ่งไฟล์"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"นำเข้าไฟล์ vCard หลายไฟล์"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"นำเข้าไฟล์ vCard ทั้งหมด"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"กำลังค้นหาข้อมูล vCard ในที่เก็บข้อมูล USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"กำลังค้นหาข้อมูล vCard ในที่เก็บข้อมูล"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"กำลังค้นหาข้อมูล vCard บนการ์ด SD"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"การสแกนที่เก็บข้อมูล USB ล้มเหลว"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"การสแกนที่เก็บข้อมูลล้มเหลว"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"การสแกนการ์ด SD ล้มเหลว"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"การสแกนที่เก็บข้อมูล USB ล้มเหลว (เหตุผล: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"การสแกนที่เก็บข้อมูลล้มเหลว (เหตุผล: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"การสแกนการ์ด SD ล้มเหลว (เหตุผล: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"ข้อผิดพลาด I/O"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"หน่วยความจำไม่เพียงพอ (ไฟล์อาจใหญ่เกินไป)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"แยกวิเคราะห์ vCard ไม่สำเร็จด้วยเหตุผลที่ไม่คาดคิด"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"รูปแบบไม่ได้รับการสนับสนุน"</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"ไม่สามารถนำเข้า vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"ไม่พบไฟล์ vCard ในที่เก็บข้อมูล USB"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"ไม่พบไฟล์ vCard ในที่เก็บข้อมูล"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"ไม่พบไฟล์ vCard บนการ์ด SD"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"รวบรวมข้อมูลเมตาของไฟล์ vCard ที่ระบุไม่สำเร็จ"</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"นำเข้าไฟล์ตั้งแต่หนึ่งไฟล์ขึ้นไปไม่สำเร็จ (%s)"</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"ส่งออกข้อมูลรายชื่อในสมุดโทรศัพท์ไม่สำเร็จ"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"ส่งออกข้อมูลรายชื่อไม่สำเร็จ"\n"เหตุผลที่ล้มเหลว: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"ไม่มีรายชื่อในสมุดโทรศัพท์ที่สามารถส่งออกได้"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"มีไฟล์ vCard มากเกินไปในที่เก็บข้อมูล USB"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"มีไฟล์ vCard มากเกินไปในที่เก็บข้อมูล"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"มีไฟล์ vCard บนการ์ด SD มากเกินไป"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"ชื่อไฟล์ที่ต้องใช้ยาวเกินไป (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"ส่งออก <xliff:g id="FILENAME">%s</xliff:g> เรียบร้อยแล้ว"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"ชื่อแบบออกเสียง"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"ชื่อกลางแบบออกเสียง"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"นามสกุลแบบออกเสียง"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"ชื่อแบบออกเสียง"</string>
<string name="account_type_format" msgid="718948015590343010">"รายชื่อในสมุดโทรศัพท์จาก <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
- <string name="from_account_format" msgid="687567483928582084">"จาก <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"ใช้ภาพนี้"</string>
<string name="contact_read_only" msgid="1203216914575723978">"ข้อมูลรายชื่อของ <xliff:g id="SOURCE">%1$s</xliff:g> แก้ไขบนอุปกรณ์นี้ไม่ได้"</string>
<string name="no_contact_details" msgid="6754415338321837001">"ไม่มีข้อมูลเพิ่มเติมสำหรับรายชื่อนี้"</string>
@@ -423,13 +427,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"ถอนการติดตั้งแอปพลิเคชันบางอย่าง"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"ลองอัปเกรดซ้ำ"</string>
<string name="search_results_searching" msgid="7755623475227227314">"กำลังค้นหา..."</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"แสดงรายการที่เลือก"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"แสดงทั้งหมด"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"เลือกทั้งหมด"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"ยกเลิกการเลือกทั้งหมด"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"ไม่ได้เลือกรายชื่อติดต่อไว้"</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"แสดงรายการที่เลือก"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"แสดงทั้งหมด"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"เลือกทั้งหมด"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"ยกเลิกการเลือกทั้งหมด"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"เลือกผู้รับ 1 ราย"</item>
+ <item quantity="other" msgid="4608837420986126229">"เลือกผู้รับไว้ <xliff:g id="COUNT">%d</xliff:g> คน"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"ไม่ได้เลือกสมุดโทรศัพท์ไว้"</string>
<string name="add_field" msgid="2384260056674995230">"เพิ่มฟิลด์อื่น"</string>
+ <string name="add_phone" msgid="4421904942555210013">"เพิ่มหมายเลขโทรศัพท์ใหม่"</string>
+ <string name="add_email" msgid="175079666329862215">"เพิ่มอีเมลใหม่"</string>
+ <string name="add_im" msgid="5158094627521120439">"เพิ่มบัญชี IM ใหม่"</string>
+ <string name="add_address" msgid="418292312672970688">"เพิ่มที่อยู่ใหม่"</string>
+ <string name="add_note" msgid="2753771325725383279">"เพิ่มบันทึกใหม่"</string>
+ <string name="add_website" msgid="4312391288948517344">"เพิ่มเว็บไซต์ใหม่"</string>
+ <string name="add_event" msgid="7488781591843886426">"เพิ่มกิจกรรมใหม่"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"เพิ่มความเกี่ยวข้องใหม่"</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>
<string name="description_star" msgid="2605854427360036550">"รายการโปรด"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 5690ee4..55d5b9e 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Default"</string>
<string name="removePhoto" msgid="4898105274130284565">"Alisin ang larawan"</string>
<string name="noContacts" msgid="8579310973261953559">"Walang mga contact."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Walang nakitang magkakatugmang mga contact."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Walang mga contact na may mga numero ng telepono."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Mga contact lang na may mga telepono"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"1 contact na may numero ng telepono"</item>
<item quantity="other" msgid="3299954047880968205">"<xliff:g id="COUNT">%d</xliff:g> (na) contact na may mga numero ng telepono"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Walang mga nakikitang contact na may mga numero ng telepono"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Walang mga contact na may mga numero ng telepono"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 contact"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> (na) contact"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Walang nakikitang mga contact"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Walang mga contact"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Walang nakikitang mga contact"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Walang mga naka-star na contact"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Walang mga contact sa <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"1 ang nakita"</item>
<item quantity="other" msgid="3852668542926965042">"<xliff:g id="COUNT">%d</xliff:g> ang nakita"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> ang nakita"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Mga Contact"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Mga Paborito"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telepono"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Log ng tawag"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Walang laman ang log ng tawag."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"I-clear ang log ng tawag"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Sigurado ka bang gusto mong i-clear ang log ng tawag?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Kini-clear ang log ng tawag"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Voicemail"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"larawan ng contact"</string>
<string name="description_minus_button" msgid="387136707700230172">"minus"</string>
<string name="description_plus_button" msgid="515164827856229880">"plus"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Di available USB storage"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Hindi available ang imbakan"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Walang SD card"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Walang nakitang imbakan na USB"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Walang natukoy na imbakan"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Walang natukoy na SD card"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Paghahanap ng vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"I-import mula sa SIM card"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Import sa imbakan na USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"I-import mula sa imbakan"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Mag-import mula sa SD card"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Export sa imbakan na USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"I-export sa imbakan"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Mag-export sa SD card"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Magbahagi ng mga nakikitang contact"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Mag-import nang isang vCard file"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Mag-import ng maramihang vCard file"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"I-import ang lahat ng mga vCard file"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Naghahanap ng vCard data sa imbakan na USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Naghahanap para sa data ng vCard sa imbakan"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Naghahanap ng data ng vCard sa SD card"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Nabigo ang pag-scan ng imbakan na USB"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Nabigo ang pag-scan ng imbakan"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Nabigo ang pag-scan sa SD card"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Nabigo ang pag-scan ng imbakan na USB (Dahilan: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Nabigo ang pag-scan ng imbakan (Dahilan: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Nabigo ang pag-scan sa SD card (Dahilan: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Error na I/O"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Hindi sapat ang memorya (maaaring masyadong malaki ang file)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Nabigong i-parse ang vCard para sa di-inaasahang dahilan"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Hindi suportado ang format."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Nabigong i-import ang vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"Walang nakitang vCard file sa imabakan ng USB"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Walang nakitang vCard file sa imbakan"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Walang nakitang vCard file sa SD card"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Nabigong kumolekta ng impormasyon na meta ng ibinigay na (mga) vCard."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Nabigo ang isa o higit pang file upang ma-import (%s)."</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Nabigong i-export ang data ng contact"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Nabigong i-export ang data ng contact."\n"Dahilan sa pagkabigo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Walang nae-export na contact"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Masyadong maraming vCard file sa imbakan na USB"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Masyadong maraming vCard file sa imbakan"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Masyadong maraming vCard file sa SD card"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Ang kinakailangang filename ay masyadong mahaba (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Tapos na ang pag-export ng <xliff:g id="FILENAME">%s</xliff:g>"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Phonetic na pangalan"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Phonetic na gitnang pangalan"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Phonetic na apelyido"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Phonetic na pangalan"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> contact"</string>
- <string name="from_account_format" msgid="687567483928582084">"mula sa <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Gamitin ang larawang ito"</string>
<string name="contact_read_only" msgid="1203216914575723978">"Ang impormasyon sa contact ng <xliff:g id="SOURCE">%1$s</xliff:g> ay hindi nae-edit sa device na ito."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Walang karagdagang impormasyon para sa contact na ito"</string>
@@ -423,13 +427,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"I-uninstall ang ilang application"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Muling subukan ang i-upgrade"</string>
<string name="search_results_searching" msgid="7755623475227227314">"Naghahanap..."</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"Ipakita ang napili"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"Ipakita lahat"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"Piliin lahat"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"Alisin sa pagkakapili ang lahat"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"Walang mga napiling kontrata."</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"Ipakita ang napili"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"Ipakita lahat"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"Piliin lahat"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"Alisin sa pagkakapili ang lahat"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"Napili ang 1 recipient"</item>
+ <item quantity="other" msgid="4608837420986126229">"Napili ang <xliff:g id="COUNT">%d</xliff:g> (na) recipient"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"Walang napiling contact."</string>
<string name="add_field" msgid="2384260056674995230">"Magdagdag ng ibang field"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Magdagdag ng bagong numero ng telepono"</string>
+ <string name="add_email" msgid="175079666329862215">"Magdagdag ng bagong email"</string>
+ <string name="add_im" msgid="5158094627521120439">"Magdagdag ng bagong IM account"</string>
+ <string name="add_address" msgid="418292312672970688">"Magdagdag ng bagong address"</string>
+ <string name="add_note" msgid="2753771325725383279">"Magdagdag ng bagong paalala"</string>
+ <string name="add_website" msgid="4312391288948517344">"Magdagdag ng bagong website"</string>
+ <string name="add_event" msgid="7488781591843886426">"Magdagdag ng bagong kaganapan"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Magdagdag ng bagong ugnayan"</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>
<string name="description_star" msgid="2605854427360036550">"paborito"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index db6c18f..190eeb4 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"Varsayılan"</string>
<string name="removePhoto" msgid="4898105274130284565">"Fotoğrafı kaldır"</string>
<string name="noContacts" msgid="8579310973261953559">"Hiçbir kişi yok."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Eşleşen kişi bulunamadı."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Telefon numarası olan hiçbir kişi yok."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Yalnızca telefonu olan kişiler"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"Telefon numarası olan 1 kişi"</item>
<item quantity="other" msgid="3299954047880968205">"Telefon numarası olan <xliff:g id="COUNT">%d</xliff:g> kişi"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Telefon numarası olan görülebilir kişi yok"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Telefon numarası olan hiçbir kişi yok"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 kişi"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> kişi"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Görülebilir kişi yok"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Hiçbir kişi yok"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Görülebilir kişi yok"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Yıldız işaretli hiçbir kişi yok"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"<xliff:g id="NAME">%s</xliff:g> içinde hiçbir kişi yok"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"1 kişi bulundu"</item>
<item quantity="other" msgid="3852668542926965042">"<xliff:g id="COUNT">%d</xliff:g> kişi bulundu"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"<xliff:g id="COUNT">%d</xliff:g> kişi bulundu"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Kişiler"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Sık Kullanılanlar"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Telefon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Çağrı kaydı"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Çağrı kaydı boş."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Çağrı kaydını temizle"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Çağrı kaydını silmek istediğinizden emin misiniz?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Çağrı kaydı temizleniyor"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Sesli Mesaj"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"kişi fotoğrafı"</string>
<string name="description_minus_button" msgid="387136707700230172">"eksi"</string>
<string name="description_plus_button" msgid="515164827856229880">"artı"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"USB depl birimi kullnlmyr"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Depolama birimi yok"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"SD kart yok"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"USB deplm birimi algılanmadı"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Hiçbir depl birimi algılanmadı"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Hiçbir SD kart tespit edilmedi"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"vCard aranıyor"</string>
<string name="import_from_sim" msgid="3859272228033941659">"SIM karttan içe aktar"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"USB depl birmndn içe aktr"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Depl biriminden içe aktar"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"SD karttan içe aktar"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"USB deplm birmn dışa aktr"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Depolama birimine aktar"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"SD karta dışa aktar"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Görülebilir kişileri paylaş"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Bir vCard dosyasını içe aktar"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Birden fazla vCard dosyasını içe aktar"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Tüm vCard dosyalarını içe aktar"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"USB depolama birimindeki vCard verileri aranıyor"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Depolama birimindeki vCard verileri aranıyor"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"SD kartta vCard verileri aranıyor"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"USB depolama birimi taraması başarısız oldu"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Depolama birimi taraması başarısız oldu"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"SD kart taranamadı"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"USB depolama birimi taraması başarısız oldu (Nedeni: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Depolama birimi taraması başarısız oldu (Nedeni: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"SD kart taraması başarısız oldu (Neden: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"G/Ç Hatası"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Bellek yetersiz (dosya çok büyük olabilir)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Beklenmedik bir nedenden dolayı vCard ayrıştırılamadı"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Biçim desteklenmiyor."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"vCard içe aktarılamadı"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"USB depolama biriminde herhangi bir vCard dosyası bulunamadı"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Depolama biriminde hiçbir vCard dosyası bulunamadı"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"SD kartta hiçbir vCard dosyası bulunamadı"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Belirtilen vCard dosyalarının meta bilgileri toplanamıyor."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"İçe aktarılamayan bir veya birden fazla dosya (%s)."</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Kişi verileri dışa aktarılamadı"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Kişi verileri dışa aktarılamadı."\n"Hata nedeni: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Dışa aktarılabilen hiçbir kişi yok"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"USB depolama biriminde çok fazla vCard dosyası var"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Depolama biriminde çok fazla vCard dosyası var"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"SD kartta çok fazla vCard dosyası var"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Gereken dosya adı çok uzun (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"<xliff:g id="FILENAME">%s</xliff:g> dosyasını dışa aktarma tamamlandı"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Fonetik adı"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetik ikinci ad"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Fonetik soyadı"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Fonetik ad"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> kişi"</string>
- <string name="from_account_format" msgid="687567483928582084">"kaynak: <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Bu fotoğrafı kullan"</string>
<string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g> kişi bilgileri bu cihazda düzenlenemez."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Bu kişi için ek bilgi yok"</string>
@@ -420,7 +424,7 @@
<string name="locale_change_in_progress" msgid="7583992153091537467">"Kişi listesi, dil değişikliğini yansıtmak üzere güncelleniyor."</string>
<string name="upgrade_in_progress" msgid="474511436863451061">"Kişi listesi güncelleniyor."</string>
<string name="upgrade_out_of_memory" msgid="6153384328042175667">"Kişilerin yeni sürüme geçirilmesi devam ediyor. "\n\n"Yeni sürüme geçirme işlemi yaklaşık <xliff:g id="SIZE_IN_MEGABYTES">%s</xliff:g> Mb dahili depolama alanı gerektirir."\n\n"Aşağıdaki seçeneklerden birini belirleyin:"</string>
- <string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Bazı uygulamaları kaldır"</string>
+ <string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Bazı uygulamaları kaldırın"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Yeni sürüme geçmeyi tekrar dene"</string>
<string name="search_results_searching" msgid="7755623475227227314">"Aranıyor..."</string>
<string name="menu_display_selected" msgid="6470001164297969034">"Seçileni göster"</string>
@@ -433,6 +437,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"Seçili kişi yok."</string>
<string name="add_field" msgid="2384260056674995230">"Başka alan ekle"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Yeni tel no ekle"</string>
+ <string name="add_email" msgid="175079666329862215">"Yeni e-posta ekle"</string>
+ <string name="add_im" msgid="5158094627521120439">"Yeni IM hesabı ekle"</string>
+ <string name="add_address" msgid="418292312672970688">"Yeni adres ekle"</string>
+ <string name="add_note" msgid="2753771325725383279">"Yeni not ekle"</string>
+ <string name="add_website" msgid="4312391288948517344">"Yeni web sitesi ekle"</string>
+ <string name="add_event" msgid="7488781591843886426">"Yeni etkinlik ekle"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Yeni ilişki ekle"</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>
<string name="description_star" msgid="2605854427360036550">"favori"</string>
@@ -474,7 +486,7 @@
<string name="social_widget_loading" msgid="3697996166985327861">"Yükleniyor …"</string>
<string name="contacts_unavailable_create_contact" msgid="7014525713871959208">"Yeni kişi oluştur"</string>
<string name="contacts_unavailable_add_account" msgid="7911101713860139754">"Bir hesapta oturum açın"</string>
- <string name="contacts_unavailable_import_contacts" msgid="4456440183590517471">"Bir dosyadaki kişileri içe aktarma"</string>
+ <string name="contacts_unavailable_import_contacts" msgid="4456440183590517471">"Bir dosyadaki kişileri içe aktar"</string>
<string name="create_group_dialog_title" msgid="6874527142828424475">"Yeni grup oluştur"</string>
<string name="create_group_item_label" msgid="5218022006186243310">"[Yeni grup oluştur]"</string>
<string name="rename_group_dialog_title" msgid="3765299704290513289">"Grubu yeniden adlandırma"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index e07db17..f87dddc 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"За умовч."</string>
<string name="removePhoto" msgid="4898105274130284565">"Видалити фото"</string>
<string name="noContacts" msgid="8579310973261953559">"Немає контакт."</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"Не знайдено відпов. контактів."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Немає контактів з номерами тел."</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Лише контакти з ном. тел."</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"1 контакт із номером телефону"</item>
<item quantity="other" msgid="3299954047880968205">"Контактів із номерами тел.: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Немає видимих контактів із номерами телефону"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"Немає контактів з номерами телефону"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 контакт"</item>
<item quantity="other" msgid="3578469907265375314">"Контактів: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Немає видимих контактів"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"Немає контактів"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"Немає видимих контактів"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"Немає контактів із зірочкою"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"Немає контактів у <xliff:g id="NAME">%s</xliff:g>"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"Знайдено 1"</item>
<item quantity="other" msgid="3852668542926965042">"Знайдено <xliff:g id="COUNT">%d</xliff:g>"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"Знайдено <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Контакти"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Вибране"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Тел."</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Журн. викл."</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Журн. викл. порожній."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Очист. журнал викл."</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Дійсно очистити журнал викликів?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Очищення журналу викликів"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Голос. пошта"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"фото контакту"</string>
<string name="description_minus_button" msgid="387136707700230172">"мінус"</string>
<string name="description_plus_button" msgid="515164827856229880">"плюс"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Носій USB недоступний"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Пам’ять недоступна"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Нема карти SD"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Носій USB не виявлено"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Пам’яті не виявлено"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Карту SD не виявлено"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Пошук даних vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Імортув. з SIM-карти"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Імпортувати з носія USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Імпорт із пам’яті"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Імортув. з карти SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Експортувати на носій USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Експорт у пам’ять"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Експорт. на карту SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Надісл. видимі контакти"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Імпортув. 1 файл vCard"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Імпортув. кілька файлів vCard"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Імпортув. всі файли vCard"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Пошук даних vCard на носії USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Пошук даних vCard у пам’яті"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Пошук даних vCard на карті SD"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Помилка сканування носія USB"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Помилка сканування пам’яті"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Помилка сканув-ня SD карти"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Помилка сканування носія USB (причина: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Помилка сканування пам’яті (причина: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Помилка сканув. SD карти (Причина: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Помилка I/O"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Недостатньо пам\'яті (можливо, файл завеликий)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Не вдал. проаналіз. vCard через неочік. прич."</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"Формат не підтримується."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Помилка імпорту vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"На носії USB не знайдено файлів vCard"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"У пам’яті не знайдено файли vCard"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"На карті SD не знайдено файлів vCard"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Помилка отримання мета-інформації файлів даної vCard."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Не вдалося імпорт. один чи кілька файлів (%s)."</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Не вдал. експорт. контактні дані"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Не вдал. експорт. контактні дані."\n"Причина помилки: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Немає доступу до експорту конт."</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Забагато файлів vCard на носії USB"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Забагато файлів vCard у пам’яті"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"На карті SD забагато файлів vCard"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Потрібна назва файлу задовга (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Експорт файлу <xliff:g id="FILENAME">%s</xliff:g> завершено"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Вимова імені"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Вимова по-батькові"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Вимова прізвища"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Вимова імені"</string>
<string name="account_type_format" msgid="718948015590343010">"Контакт <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
- <string name="from_account_format" msgid="687567483928582084">"з <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Викор. це фото"</string>
<string name="contact_read_only" msgid="1203216914575723978">"Конт. інф-цію <xliff:g id="SOURCE">%1$s</xliff:g> неможливо редагув. на цьому пристрої."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Немає додатк. інформації для цього контакту"</string>
@@ -423,13 +427,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Видалити деякі програми"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Повтор. оновл."</string>
<string name="search_results_searching" msgid="7755623475227227314">"Пошук..."</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"Показати вибране"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"Показати все"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"Вибрати все"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"Відмінити все"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"Контакти не вибрано."</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"Показати вибране"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"Показати все"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"Вибрати все"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"Скасувати все"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"Вибрано 1 отримувача"</item>
+ <item quantity="other" msgid="4608837420986126229">"Вибрано отримувачів: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"Контакти не вибрано."</string>
<string name="add_field" msgid="2384260056674995230">"Додати ще одне поле"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Додати нов. номер тел."</string>
+ <string name="add_email" msgid="175079666329862215">"Додати нову ел. адресу"</string>
+ <string name="add_im" msgid="5158094627521120439">"Дод. нов.обл.зап. чату"</string>
+ <string name="add_address" msgid="418292312672970688">"Додати нову адресу"</string>
+ <string name="add_note" msgid="2753771325725383279">"Додати нову примітку"</string>
+ <string name="add_website" msgid="4312391288948517344">"Додати новий веб-сайт"</string>
+ <string name="add_event" msgid="7488781591843886426">"Додати нову подію"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Додати нові стосунки"</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>
<string name="description_star" msgid="2605854427360036550">"вибране"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 32002de..7571f61 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -89,12 +89,13 @@
<string name="photoPickerNotFoundText" product="tablet" msgid="6247290728908599701">"Không có ảnh nào trong máy tính bảng."</string>
<string name="photoPickerNotFoundText" product="default" msgid="431331662154342581">"Không có ảnh nào trong điện thoại."</string>
<string name="attach_photo_dialog_title" msgid="5599827035558557169">"Ảnh của liên hệ"</string>
- <string name="customLabelPickerTitle" msgid="1081475101983255212">"Tên nhãn tuỳ chỉnh"</string>
+ <string name="customLabelPickerTitle" msgid="1081475101983255212">"Tên nhãn tùy chỉnh"</string>
<string name="menu_displayGroup" msgid="5655505437727616553">"Tuỳ chọn hiển thị"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"Gửi cuộc gọi trực tiếp tới thư thoại"</string>
<string name="default_ringtone" msgid="9099988849649827972">"Mặc định"</string>
<string name="removePhoto" msgid="4898105274130284565">"Xóa ảnh"</string>
<string name="noContacts" msgid="8579310973261953559">"Không có liên hệ nào."</string>
+ <string name="noGroups" msgid="8614664663561385253">"Không có nhóm nào."</string>
<string name="noMatchingContacts" msgid="4266283206853990471">"Không tìm thấy liên hệ nào phù hợp."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Không có liên hệ nào có số điện thoại"</string>
<string name="showFilterPhones" msgid="4184858075465653970">"Chỉ các liên hệ có số điện thoại"</string>
@@ -134,6 +135,7 @@
<item quantity="other" msgid="7988132539476575389">"Đã tìm thấy <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"Danh bạ"</string>
+ <string name="contactsGroupsLabel" msgid="2841971472518003524">"Nhóm"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Mục ưa thích"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"Điện thoại"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Nhật ký cuộc gọi"</string>
@@ -149,6 +151,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"Nhật ký cuộc gọi trống."</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Xoá nhật ký cuộc gọi"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"Bạn có chắc chắn muốn xoá nhật ký cuộc gọi không?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Đang xóa nhật ký cuộc gọi"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Thư thoại"</string>
@@ -208,32 +211,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"ảnh của liên hệ"</string>
<string name="description_minus_button" msgid="387136707700230172">"trừ"</string>
<string name="description_plus_button" msgid="515164827856229880">"cộng"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"Bộ nhớ USB không khả dụng"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"Bộ nhớ không khả dụng"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"Không có thẻ SD nào"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"Không phát hiện bộ nhớ USB nào"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"Không phát hiện bộ nhớ nào"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"Không phát hiện thẻ SD nào"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"Đang tìm kiếm vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"Nhập từ thẻ SIM"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"Nhập từ bộ nhớ USB"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"Nhập từ bộ nhớ"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"Nhập từ thẻ SD"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"Xuất sang bộ nhớ USB"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"Xuất sang bộ nhớ"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"Xuất sang thẻ SD"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"Chia sẻ liên hệ hiển thị"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"Nhập một tệp vCard"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"Nhập nhiều tệp vCard"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"Nhập tất cả tệp vCard"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"Đang tìm kiếm dữ liệu vCard trong bộ nhớ USB"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"Đang tìm kiếm dữ liệu vCard trong bộ nhớ"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"Đang tìm dữ liệu vCard trên thẻ SD"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"Quét bộ nhớ USB không thành công"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"Quét bộ nhớ không thành công"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"Quét thẻ SD không thành công"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"Quét bộ nhớ USB không thành công (Lý do: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"Quét bộ nhớ không thành công (Lý do: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"Quét thẻ SD không thành công (Lý do: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Lỗi I/O"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Bộ nhớ không đủ (tệp có thể quá lớn)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"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="294499264620201243">"Định dạng không được hỗ trợ."</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"Không thể nhập vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"Không tìm thấy tệp vCard trong bộ lưu trữ USB"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Không tìm thấy tệp vCard nào trong bộ nhớ"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Không tìm thấy tệp vCard trên thẻ SD"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Không thể thu thập siêu thông tin của (các) tệp vCard cho trước."</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Không thể nhập một hoặc nhiều tệp (%s)."</string>
@@ -259,7 +262,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"Không thể xuất dữ liệu liên hệ"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"Không thể xuất dữ liệu liên hệ."\n"Lý do không thành công: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Không có liên hệ có thể xuất nào"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"Quá nhiều tệp vCard trong bộ nhớ USB"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Quá nhiều tệp vCard trong bộ nhớ"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Quá nhiều tệp vCard trên thẻ SD"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Tên tệp yêu cầu quá dài (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Đã xuất xong <xliff:g id="FILENAME">%s</xliff:g>"</string>
@@ -397,8 +400,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"Tên đúng phát âm"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"Tên đệm đúng phát âm"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"Họ đúng phát âm"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Tên theo phiên âm"</string>
<string name="account_type_format" msgid="718948015590343010">"Liên hệ <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
- <string name="from_account_format" msgid="687567483928582084">"từ <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"Sử dụng ảnh này"</string>
<string name="contact_read_only" msgid="1203216914575723978">"Không thể chỉnh sửa thông tin liên hệ <xliff:g id="SOURCE">%1$s</xliff:g> trên thiết bị này."</string>
<string name="no_contact_details" msgid="6754415338321837001">"Không có thông tin bổ sung cho liên hệ này"</string>
@@ -420,13 +425,24 @@
<string name="upgrade_out_of_memory_uninstall" msgid="1721798828992091432">"Gỡ cài đặt một số ứng dụng"</string>
<string name="upgrade_out_of_memory_retry" msgid="8431289830472724609">"Thử lại nâng cấp"</string>
<string name="search_results_searching" msgid="7755623475227227314">"Đang tìm kiếm..."</string>
- <!-- outdated translation 7509416164257469826 --> <string name="menu_display_selected" msgid="6470001164297969034">"Hiển thị mục đã chọn"</string>
- <!-- outdated translation 6157266246378155002 --> <string name="menu_display_all" msgid="8887488642609786198">"Hiển thị tất cả"</string>
- <!-- outdated translation 6071138984118728586 --> <string name="menu_select_all" msgid="621719255150713545">"Chọn tất cả"</string>
- <!-- outdated translation 6876179536556771017 --> <string name="menu_select_none" msgid="7093222469852132345">"Bỏ chọn tất cả"</string>
- <!-- no translation found for multiple_picker_title:other (4608837420986126229) -->
- <!-- outdated translation 2762557778532289842 --> <string name="no_contacts_selected" msgid="5877803471037324613">"Không có địa chỉ liên hệ nào được chọn."</string>
+ <string name="menu_display_selected" msgid="6470001164297969034">"Hiển thị mục đã chọn"</string>
+ <string name="menu_display_all" msgid="8887488642609786198">"Hiển thị tất cả"</string>
+ <string name="menu_select_all" msgid="621719255150713545">"Chọn tất cả"</string>
+ <string name="menu_select_none" msgid="7093222469852132345">"Bỏ chọn tất cả"</string>
+ <plurals name="multiple_picker_title">
+ <item quantity="one" msgid="4761009734586319101">"Đã chọn 1 người nhận"</item>
+ <item quantity="other" msgid="4608837420986126229">"Đã chọn <xliff:g id="COUNT">%d</xliff:g> người nhận"</item>
+ </plurals>
+ <string name="no_contacts_selected" msgid="5877803471037324613">"Không có địa chỉ liên hệ nào được chọn."</string>
<string name="add_field" msgid="2384260056674995230">"Thêm trường khác"</string>
+ <string name="add_phone" msgid="4421904942555210013">"Thêm số điện thoại mới"</string>
+ <string name="add_email" msgid="175079666329862215">"Thêm email mới"</string>
+ <string name="add_im" msgid="5158094627521120439">"Thêm tài khoản IM mới"</string>
+ <string name="add_address" msgid="418292312672970688">"Thêm địa chỉ mới"</string>
+ <string name="add_note" msgid="2753771325725383279">"Thêm chú thích mới"</string>
+ <string name="add_website" msgid="4312391288948517344">"Thêm trang web mới"</string>
+ <string name="add_event" msgid="7488781591843886426">"Thêm sự kiện mới"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"Thêm mối quan hệ mới"</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>
<string name="description_star" msgid="2605854427360036550">"Yêu thích"</string>
diff --git a/res/values-xlarge/dimens.xml b/res/values-xlarge/dimens.xml
index 6ffbb31..2d39186 100644
--- a/res/values-xlarge/dimens.xml
+++ b/res/values-xlarge/dimens.xml
@@ -16,10 +16,19 @@
<resources>
<dimen name="edit_photo_size">96dip</dimen>
<dimen name="aggregation_suggestion_icon_size">64dip</dimen>
+ <dimen name="editor_type_label_width">180dip</dimen>
+ <dimen name="editor_field_spinner_text_size">15sp</dimen>
+ <dimen name="editor_round_button_padding_left">8dip</dimen>
+ <dimen name="editor_round_button_padding_right">8dip</dimen>
+ <dimen name="editor_field_top_padding">12dip</dimen>
+ <dimen name="editor_field_bottom_padding">12dip</dimen>
+ <dimen name="detail_item_side_margin">19dip</dimen>
<dimen name="quick_contact_width">356dip</dimen>
<dimen name="contact_name_text_size">26sp</dimen>
<dimen name="action_bar_filter_min_width">120dip</dimen>
<dimen name="action_bar_filter_max_width">120dip</dimen>
<dimen name="action_bar_search_max_width">300dip</dimen>
<dimen name="action_bar_search_spacing">12dip</dimen>
+ <dimen name="shortcut_icon_size">64dip</dimen>
+ <dimen name="list_section_height">37dip</dimen>
</resources>
diff --git a/res/values-xlarge/donottranslate_config.xml b/res/values-xlarge/donottranslate_config.xml
new file mode 100644
index 0000000..fcb7da9
--- /dev/null
+++ b/res/values-xlarge/donottranslate_config.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<resources>
+ <bool name="config_use_two_panes">true</bool>
+</resources>
diff --git a/res/values-xlarge/styles.xml b/res/values-xlarge/styles.xml
index e601590..dcb32ad 100644
--- a/res/values-xlarge/styles.xml
+++ b/res/values-xlarge/styles.xml
@@ -57,9 +57,6 @@
<item name="list_item_header_text_size">14sp</item>
</style>
- <style name="ContactsPreferencesTheme" parent="@android:Theme.Holo.Light">
- </style>
-
<style name="CustomContactListFilterTheme" parent="@android:Theme.Holo.Light.Dialog">
</style>
@@ -105,4 +102,15 @@
<item name="android:windowNoDisplay">true</item>
<item name="android:windowIsFloating">true</item>
</style>
+
+ <style name="ContactDetailItemType">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
+ <item name="android:textColor">@color/detail_item_type_color</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:paddingTop">5dip</item>
+ </style>
</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 735b74f..c566ad1 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"默认日历"</string>
<string name="removePhoto" msgid="4898105274130284565">"删除照片"</string>
<string name="noContacts" msgid="8579310973261953559">"没有联系人。"</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"未找到匹配的联系人。"</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"没有联系人拥有电话号码。"</string>
<string name="showFilterPhones" msgid="4184858075465653970">"仅显示有电话号码的联系人"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"1 位联系人有电话号码"</item>
<item quantity="other" msgid="3299954047880968205">"<xliff:g id="COUNT">%d</xliff:g> 位联系人有电话号码"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"显示的联系人都没有电话号码。"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"没有联系人拥有电话号码"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 位联系人"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> 位联系人"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"未显示任何联系人"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"没有联系人"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"未显示任何联系人"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"没有已加星标的联系人"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"“<xliff:g id="NAME">%s</xliff:g>”中没有联系人"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"找到 1 个联系人"</item>
<item quantity="other" msgid="3852668542926965042">"找到 <xliff:g id="COUNT">%d</xliff:g> 个联系人"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"找到 <xliff:g id="COUNT">%d</xliff:g> 个联系人"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"通讯录"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"收藏"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"拨号"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"通话记录"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"通话记录为空。"</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"清除通话记录"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"确定要清除通话记录吗?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"正在清除通话记录"</string>
<string name="imei" msgid="3045126336951684285">"移动通信国际识别码"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"语音信箱"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"联系人照片"</string>
<string name="description_minus_button" msgid="387136707700230172">"删除"</string>
<string name="description_plus_button" msgid="515164827856229880">"添加"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"不存在 USB 存储设备"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"存储设备不存在"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"无 SD 卡"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"未检测到 USB 存储设备"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"未检测到存储设备"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"未检测到 SD 卡"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"正在搜索 vCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"从 SIM 卡导入"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"从 USB 存储设备导入"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"从存储设备导入"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"从 SD 卡导入"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"导出到 USB 存储设备"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"导出到存储设备"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"导出到 SD 卡"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"分享可见的联系人"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"导入一个 vCard 文件"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"导入多个 vCard 文件"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"导入所有 vCard 文件"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"正在 USB 存储设备中搜索 vCard 文件"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"正在存储设备中搜索 vCard 文件"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"正在 SD 卡中搜索 vCard 数据"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"扫描 USB 存储设备时失败"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"扫描存储设备时失败"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"扫描 SD 卡失败"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"扫描 USB 存储设备时失败(原因:“<xliff:g id="FAIL_REASON">%s</xliff:g>”)"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"扫描存储设备时失败(原因:“<xliff:g id="FAIL_REASON">%s</xliff:g>”)"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"扫描 SD 卡失败(原因:“<xliff:g id="FAIL_REASON">%s</xliff:g>”)"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"I/O 错误"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"存储器空间不足(文件可能过大)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"由于意外原因而无法解析 vCard"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"不支持此格式。"</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"未能导入 vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"未在 USB 存储设备中找到 vCard 文件"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"未在存储设备中找到 vCard 文件"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"未在 SD 卡上找到 vCard 文件"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"无法收集指定的 vCard 文件的元信息。"</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"一个或多个文件导入失败 (%s)。"</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"导出联系人数据失败"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"导出联系人数据失败。"\n"失败原因:“<xliff:g id="FAIL_REASON">%s</xliff:g>”"</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"没有可导出的联系人"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"USB 存储设备中的 vCard 文件太多"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"存储设备中的 vCard 文件过多"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"SD 卡中的 vCard 文件太多"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"所需文件名太长(“<xliff:g id="FILENAME">%s</xliff:g>”)"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"导出 <xliff:g id="FILENAME">%s</xliff:g> 已完成"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"名字拼音"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"中间名拼音"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"姓氏拼音"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"姓名拼音"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> 联系人"</string>
- <string name="from_account_format" msgid="687567483928582084">"来自 <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"使用此照片"</string>
<string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g> 联系人信息在此设备上不可编辑。"</string>
<string name="no_contact_details" msgid="6754415338321837001">"无此联系人的其他信息"</string>
@@ -433,6 +437,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"未选择联系人。"</string>
<string name="add_field" msgid="2384260056674995230">"添加其他字段"</string>
+ <string name="add_phone" msgid="4421904942555210013">"添加新电话号码"</string>
+ <string name="add_email" msgid="175079666329862215">"添加新电子邮件地址"</string>
+ <string name="add_im" msgid="5158094627521120439">"添加新即时通讯帐户"</string>
+ <string name="add_address" msgid="418292312672970688">"添加新地址"</string>
+ <string name="add_note" msgid="2753771325725383279">"添加新备注"</string>
+ <string name="add_website" msgid="4312391288948517344">"添加新网站"</string>
+ <string name="add_event" msgid="7488781591843886426">"添加新活动"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"添加新关系"</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>
<string name="description_star" msgid="2605854427360036550">"收藏"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 5f11531..5bb8550 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -75,7 +75,7 @@
<string name="label_ringtone" msgid="8833166825330686244">"鈴聲"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"姓名拼音"</string>
<string name="ghostData_company" msgid="5414421120553765775">"公司"</string>
- <string name="ghostData_title" msgid="7496735200318496110">"標題"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"職稱"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"聯絡人不存在。"</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"建立新聯絡人"</string>
<string name="phoneLabelsGroup" msgid="6468091477851199285">"電話"</string>
@@ -95,6 +95,8 @@
<string name="default_ringtone" msgid="9099988849649827972">"預設值"</string>
<string name="removePhoto" msgid="4898105274130284565">"移除相片"</string>
<string name="noContacts" msgid="8579310973261953559">"沒有聯絡人。"</string>
+ <!-- no translation found for noGroups (8614664663561385253) -->
+ <skip />
<string name="noMatchingContacts" msgid="4266283206853990471">"找不到符合的聯絡人。"</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"沒有包含電話號碼的聯絡人資訊。"</string>
<string name="showFilterPhones" msgid="4184858075465653970">"僅顯示有電話號碼的聯絡人"</string>
@@ -114,18 +116,15 @@
<item quantity="one" msgid="3015357862286673986">"1 位有電話號碼的聯絡人"</item>
<item quantity="other" msgid="3299954047880968205">"<xliff:g id="COUNT">%d</xliff:g> 位有電話號碼的聯絡人"</item>
</plurals>
- <!-- outdated translation 3100001705005525307 --> <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"在可顯示的聯絡人中,找不到附有電話號碼的聯絡人"</string>
+ <string name="listTotalPhoneContactsZero" msgid="6968813857632984319">"所有聯絡人資訊中都沒有電話號碼"</string>
<plurals name="listTotalAllContacts">
<item quantity="one" msgid="3405747744700823280">"1 位聯絡人"</item>
<item quantity="other" msgid="3578469907265375314">"<xliff:g id="COUNT">%d</xliff:g> 位聯絡人"</item>
</plurals>
- <!-- outdated translation 5917810721329112813 --> <string name="listTotalAllContactsZero" msgid="1889349925514589304">"沒有可顯示的聯絡人"</string>
- <!-- no translation found for listTotalAllContactsZeroCustom (4058252141420128998) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroStarred (5391630590684099117) -->
- <skip />
- <!-- no translation found for listTotalAllContactsZeroGroup (5448979458248027615) -->
- <skip />
+ <string name="listTotalAllContactsZero" msgid="1889349925514589304">"沒有聯絡人"</string>
+ <string name="listTotalAllContactsZeroCustom" msgid="4058252141420128998">"沒有可顯示的聯絡人"</string>
+ <string name="listTotalAllContactsZeroStarred" msgid="5391630590684099117">"沒有已加星號的聯絡人"</string>
+ <string name="listTotalAllContactsZeroGroup" msgid="5448979458248027615">"「<xliff:g id="NAME">%s</xliff:g>」中沒有聯絡人"</string>
<plurals name="listFoundAllContacts">
<item quantity="one" msgid="5517063038754171134">"找到 1 位聯絡人"</item>
<item quantity="other" msgid="3852668542926965042">"找到 <xliff:g id="COUNT">%d</xliff:g> 位聯絡人"</item>
@@ -137,6 +136,8 @@
<item quantity="other" msgid="7988132539476575389">"找到 <xliff:g id="COUNT">%d</xliff:g> 位聯絡人"</item>
</plurals>
<string name="contactsIconLabel" msgid="7666609097606552806">"聯絡人"</string>
+ <!-- no translation found for contactsGroupsLabel (2841971472518003524) -->
+ <skip />
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"我的最愛"</string>
<string name="dialerIconLabel" msgid="6500826552823403796">"電話"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"通話記錄"</string>
@@ -152,6 +153,7 @@
<string name="recentCalls_empty" msgid="247053222448663107">"無通話記錄。"</string>
<string name="clearCallLogConfirmation_title" msgid="718072843006222703">"清除通話記錄"</string>
<string name="clearCallLogConfirmation" msgid="7625927669136267636">"確定要清除通話記錄嗎?"</string>
+ <string name="clearCallLogProgress_title" msgid="6870412675015656948">"正在清除通話記錄"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
<string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"語音留言"</string>
@@ -211,32 +213,32 @@
<string name="description_contact_photo" msgid="3387458082667894062">"聯絡人相片"</string>
<string name="description_minus_button" msgid="387136707700230172">"負號"</string>
<string name="description_plus_button" msgid="515164827856229880">"加號"</string>
- <string name="no_sdcard_title" product="nosdcard" msgid="5362631473262100989">"沒有可用的 USB 儲存裝置"</string>
+ <string name="no_sdcard_title" product="nosdcard" msgid="8543619259870877473">"儲存裝置無法使用"</string>
<string name="no_sdcard_title" product="default" msgid="5911758680339949273">"無 SD 卡"</string>
- <string name="no_sdcard_message" product="nosdcard" msgid="8045830739790534254">"未偵測到 USB 儲存裝置"</string>
+ <string name="no_sdcard_message" product="nosdcard" msgid="1334170151822669976">"未偵測到儲存裝置"</string>
<string name="no_sdcard_message" product="default" msgid="6019391476490445358">"未偵測到 SD 卡"</string>
<string name="searching_vcard_title" msgid="4970508055399376813">"正在搜尋 VCard"</string>
<string name="import_from_sim" msgid="3859272228033941659">"從 SIM 卡匯入"</string>
- <string name="import_from_sdcard" product="nosdcard" msgid="8294728696808674154">"從 USB 儲存裝置匯入"</string>
+ <string name="import_from_sdcard" product="nosdcard" msgid="8668347930577565175">"從儲存裝置匯入"</string>
<string name="import_from_sdcard" product="default" msgid="8550360976693202816">"從 SD 卡匯入"</string>
- <string name="export_to_sdcard" product="nosdcard" msgid="7201274701382901259">"匯出到 USB 儲存裝置"</string>
+ <string name="export_to_sdcard" product="nosdcard" msgid="6092815580965201089">"匯出到儲存裝置"</string>
<string name="export_to_sdcard" product="default" msgid="2597105442616166277">"匯出至 SD 卡"</string>
<string name="share_visible_contacts" msgid="890150378880783797">"分享正常顯示的聯絡人"</string>
<string name="import_one_vcard_string" msgid="9059163467020328433">"匯入一個 vCard 檔案"</string>
<string name="import_multiple_vcard_string" msgid="3810226492811062392">"匯入多個 vCard 檔案"</string>
<string name="import_all_vcard_string" msgid="5518136113853448474">"匯入所有 vCard 檔案"</string>
- <string name="searching_vcard_message" product="nosdcard" msgid="8214795338181412751">"正在 USB 儲存裝置中搜尋 vCard 資料"</string>
+ <string name="searching_vcard_message" product="nosdcard" msgid="996170203695743981">"正在搜尋儲存裝置中的 vCard 資料"</string>
<string name="searching_vcard_message" product="default" msgid="6917522333561434546">"在 SD 卡上搜尋 VCard 資料"</string>
- <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="7447077516493667568">"掃描 USB 儲存裝置失敗"</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard" msgid="6957414493948497249">"無法掃描儲存裝置"</string>
<string name="scanning_sdcard_failed_title" product="default" msgid="3506782007953167180">"無法掃描 SD 卡"</string>
- <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="5645544323676912703">"掃描 USB 儲存裝置失敗 (原因:「<xliff:g id="FAIL_REASON">%s</xliff:g>」)"</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard" msgid="4106156155205860626">"無法掃描儲存裝置 (原因:「<xliff:g id="FAIL_REASON">%s</xliff:g>」)"</string>
<string name="scanning_sdcard_failed_message" product="default" msgid="3761992500690182922">"無法掃描 SD 卡 (原因:「<xliff:g id="FAIL_REASON">%s</xliff:g>」)"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"I/O 錯誤"</string>
<string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"記憶體不足 (檔案可能過大)"</string>
<string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"因未預期原因,無法剖析 VCard"</string>
<string name="fail_reason_not_supported" msgid="294499264620201243">"不支援這種格式。"</string>
<string name="vcard_import_failed" msgid="7718330063493653085">"無法匯入 vCard"</string>
- <string name="import_failure_no_vcard_file" product="nosdcard" msgid="8809370398968655782">"在 USB 儲存裝置中找不到 vCard 檔案"</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"在儲存裝置中找不到 vCard 檔案"</string>
<string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"在 SD 卡上找不到 vCard 檔案"</string>
<string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"無法從指定的 vCard 檔案收集中繼資料。"</string>
<string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"無法匯入一或多個檔案 (%s)。"</string>
@@ -262,7 +264,7 @@
<string name="exporting_contact_failed_title" msgid="585823094820602526">"無法匯出聯絡人資料"</string>
<string name="exporting_contact_failed_message" msgid="4151348002470298092">"匯出聯絡人資料失敗。"\n"失敗原因:「<xliff:g id="FAIL_REASON">%s</xliff:g>」"</string>
<string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"沒有可匯出的聯絡人"</string>
- <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="2638638826954895225">"USB 儲存裝置中的 vCard 檔案過多"</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"儲存裝置中的 vCard 檔案過多"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"SD 卡中的 VCard 檔案過多"</string>
<string name="fail_reason_too_long_filename" msgid="1915716071321839166">"要求的檔案名稱過長 (「<xliff:g id="FILENAME">%s</xliff:g>」)"</string>
<string name="exporting_vcard_finished_title" msgid="4259736138838583213">"已完成匯出 <xliff:g id="FILENAME">%s</xliff:g>"</string>
@@ -400,8 +402,10 @@
<string name="name_phonetic_given" msgid="6853570431394449191">"名字 (拼音)"</string>
<string name="name_phonetic_middle" msgid="8643721493320405200">"中間名 (拼音)"</string>
<string name="name_phonetic_family" msgid="462095502140180305">"姓氏 (拼音)"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"姓名拼音"</string>
<string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> 聯絡人"</string>
- <string name="from_account_format" msgid="687567483928582084">"來自 <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <!-- no translation found for from_account_format (4469138575127580203) -->
+ <skip />
<string name="use_photo_as_primary" msgid="8807110122951157246">"使用此相片"</string>
<string name="contact_read_only" msgid="1203216914575723978">"無法在此裝置編輯 <xliff:g id="SOURCE">%1$s</xliff:g> 的聯絡人資訊"</string>
<string name="no_contact_details" msgid="6754415338321837001">"沒有此聯絡人的其他資訊"</string>
@@ -433,6 +437,14 @@
</plurals>
<string name="no_contacts_selected" msgid="5877803471037324613">"未選取任何聯絡人。"</string>
<string name="add_field" msgid="2384260056674995230">"新增其他欄位"</string>
+ <string name="add_phone" msgid="4421904942555210013">"新增電話號碼"</string>
+ <string name="add_email" msgid="175079666329862215">"新增電子郵件"</string>
+ <string name="add_im" msgid="5158094627521120439">"新增即時通訊帳戶"</string>
+ <string name="add_address" msgid="418292312672970688">"新增地址"</string>
+ <string name="add_note" msgid="2753771325725383279">"新增附註"</string>
+ <string name="add_website" msgid="4312391288948517344">"新增網站"</string>
+ <string name="add_event" msgid="7488781591843886426">"新增活動"</string>
+ <string name="add_relationship" msgid="3083762399737240006">"新增關係"</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>
<string name="description_star" msgid="2605854427360036550">"我的最愛"</string>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 69f92ad..ace8869 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -21,10 +21,16 @@
<color name="quickcontact_disambig_divider">#afafaf</color>
<color name="edit_divider">#ff666666</color>
+
+ <!-- Color of the background of the contact detail and editor pages -->
+ <color name="background_primary">#FFFFFF</color>
+
<color name="background_secondary">#ff202020</color>
<color name="translucent_search_background">#cc000000</color>
+ <color name="account_selection_background">#ff000000</color>
+
<!-- Color used for the letter in the A-Z section header -->
<color name="section_header_text_color">#ff999999</color>
@@ -39,4 +45,7 @@
<!-- Color of the text indicating the type of entry (e.g. Home, Work etc) -->
<color name="detail_item_type_color">#B4B4B4</color>
+
+ <!-- Color of the text indicating the type of entry (e.g. Home, Work etc) -->
+ <color name="detail_header_view_text_color">#FFFFFF</color>
</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
new file mode 100644
index 0000000..6ebaa1f
--- /dev/null
+++ b/res/values/config.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<resources>
+
+ <!-- Amount of memory in bytes allocated for photo cache -->
+ <integer name="config_photo_cache_max_bytes">2000000</integer>
+
+ <!-- Number of decoded photo bitmaps retained in an LRU cache -->
+ <integer name="config_photo_cache_max_bitmaps">48</integer>
+</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 0b2cffd..ff7d873 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
<resources>
- <dimen name="edit_photo_size">76dip</dimen>
+ <dimen name="edit_photo_size">120dip</dimen>
<!-- The height of the ScrollingTabWidget -->
<dimen name="tab_height">40dip</dimen>
@@ -26,6 +26,9 @@
<dimen name="aggregation_suggestion_icon_size">40dip</dimen>
<dimen name="account_selector_popup_width">400dip</dimen>
+ <dimen name="account_selector_icon_size">30dip</dimen>
+ <dimen name="account_selector_min_item_height">48dip</dimen>
+ <dimen name="account_selector_horizontal_margin">6dip</dimen>
<dimen name="photo_action_popup_width">400dip</dimen>
@@ -35,20 +38,53 @@
<dimen name="quick_contact_width">352dip</dimen>
<!-- Padding of the rounded plus/minus/expand/collapse buttons in the editor -->
- <dimen name="editor_round_button_padding_left">8dip</dimen>
- <dimen name="editor_round_button_padding_right">8dip</dimen>
+ <dimen name="editor_round_button_padding_left">4dip</dimen>
+ <dimen name="editor_round_button_padding_right">4dip</dimen>
<dimen name="editor_round_button_padding_top">8dip</dimen>
<dimen name="editor_round_button_padding_bottom">8dip</dimen>
+ <!-- Font size for the structured name in the contact detail page -->
+ <dimen name="editor_structured_name_text_size">25sp</dimen>
+
<!-- Width of the Type-Label in the Editor -->
- <dimen name="editor_type_label_width">180dip</dimen>
-
+ <dimen name="editor_type_label_width">120dip</dimen>
+
+ <!-- Left padding of a field in the Editor -->
+ <dimen name="editor_field_left_padding">5dip</dimen>
+
+ <!-- Top padding of a field in the Editor -->
+ <dimen name="editor_field_top_padding">10dip</dimen>
+
+ <!-- Bottom padding of a field in the Editor -->
+ <dimen name="editor_field_bottom_padding">5dip</dimen>
+
<!-- Minimum height of a row in the Editor -->
<dimen name="editor_min_line_item_height">48dip</dimen>
+ <!-- Font size used for the value of a field in the contact editor. -->
+ <dimen name="editor_field_text_size">18sp</dimen>
+
+ <!-- Font size used for the title of a field in the contact editor. -->
+ <dimen name="editor_field_title_text_size">15sp</dimen>
+
+ <!-- Font size for the entries in a spinner in the contact editor. -->
+ <dimen name="editor_field_spinner_text_size">10sp</dimen>
+
+ <!-- Left and right padding for a contact detail item -->
+ <dimen name="detail_item_icon_margin">10dip</dimen>
+
+ <!-- Left and right padding for a contact detail item -->
+ <dimen name="detail_item_side_margin">10dip</dimen>
+
<!-- Minimum height of a row in the contact detail -->
<dimen name="detail_min_line_item_height">48dip</dimen>
+ <!-- Width of a contact detail item type (i.e. Nickname or Website). -->
+ <dimen name="detail_item_type_width">164dip</dimen>
+
+ <!-- Font size for the display name in header of the contact detail page -->
+ <dimen name="detail_header_name_text_size">30sp</dimen>
+
<!-- Padding to be used between a visible scrollbar and the contact list -->
<dimen name="list_visible_scrollbar_padding">40dip</dimen>
@@ -58,9 +94,6 @@
<!-- Font size used for the social status in the widget -->
<dimen name="widget_text_size_snippet">13sp</dimen>
- <!-- Font size used for the contact name in the detail and the editor -->
- <dimen name="contact_name_text_size">18sp</dimen>
-
<!-- Minimum width of the filter selector in the action bar -->
<dimen name="action_bar_filter_min_width">100dip</dimen>
@@ -73,4 +106,9 @@
<!-- Spacing on the left the search field in the action bar -->
<dimen name="action_bar_search_spacing">12dip</dimen>
+ <!-- Size of the shortcut icon. 0dip means: use the system default -->
+ <dimen name="shortcut_icon_size">0dip</dimen>
+
+ <!-- Height of list sections (A, B, C) that show the first character of the contacts -->
+ <dimen name="list_section_height">25dip</dimen>
</resources>
diff --git a/res/values/donottranslate_config.xml b/res/values/donottranslate_config.xml
index cad2a63..e310953 100644
--- a/res/values/donottranslate_config.xml
+++ b/res/values/donottranslate_config.xml
@@ -96,4 +96,11 @@
<!-- 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, phonetic name is included in the contact editor by default -->
+ <bool name="config_editor_include_phonetic_name">false</bool>
+
+ <!-- If true, Contacts uses two panes: List and Detail. If false, Details are
+ shown in their own screens. This flag must be in sync with the layout definitions. -->
+ <bool name="config_use_two_panes">false</bool>
</resources>
diff --git a/res/values/ids.xml b/res/values/ids.xml
index 1a553d1..2de327a 100644
--- a/res/values/ids.xml
+++ b/res/values/ids.xml
@@ -18,7 +18,6 @@
<item type="id" name="data"/>
<item type="id" name="header_phones"/>
<item type="id" name="dialog_sync_add"/>
- <item type="id" name="dialog_import_export"/>
<!-- For vcard.ImportVCardActivity -->
<item type="id" name="dialog_searching_vcard"/>
@@ -39,9 +38,6 @@
<item type="id" name="dialog_delete_contact_confirmation"/>
<item type="id" name="dialog_delete_contact_loader_id" />
- <!-- For ImportExportInteraction -->
- <item type="id" name="dialog_import_export_options"/>
-
<!-- For ExportVCardActivity -->
<item type="id" name="dialog_export_confirmation"/>
<item type="id" name="dialog_exporting_vcard"/>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d09904a..5605d25 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -264,6 +264,9 @@
<!-- The text displayed when the contacts list is empty while displaying all contacts -->
<string name="noContacts">No contacts.</string>
+ <!-- The text displayed when the groups list is empty while displaying all groups [CHAR LIMIT=NONE] -->
+ <string name="noGroups">No groups.</string>
+
<!-- The text displayed when the contacts list is empty while displaying results after searching contacts -->
<string name="noMatchingContacts">No matching contacts found.</string>
@@ -349,6 +352,9 @@
<!-- The description text for the contacts tab. Space is limited for this string, so the shorter the better -->
<string name="contactsIconLabel">Contacts</string>
+ <!-- The description text for the groups tab. Space is limited for this string, so the shorter the better -->
+ <string name="contactsGroupsLabel">Groups</string>
+
<!-- The description text for the favorites tab. Space is limited for this string, so the shorter the better -->
<string name="contactsFavoritesLabel">Favorites</string>
@@ -388,6 +394,9 @@
<!-- Confirmation dialog for clearing the call log -->
<string name="clearCallLogConfirmation">Are you sure you want to clear the call log?</string>
+ <!-- Title of the "Clearing call log" progress-dialog [CHAR LIMIT=35] -->
+ <string name="clearCallLogProgress_title">Clearing call log</string>
+
<!-- The title of a dialog that displays the IMEI of the phone -->
<string name="imei">IMEI</string>
@@ -680,13 +689,13 @@
-->
<string name="description_plus_button">plus</string>
- <!-- Dialog title shown when USB storage does not exist [CHAR LIMIT=25] -->
- <string name="no_sdcard_title" product="nosdcard">USB storage unavailable</string>
+ <!-- Dialog title shown when (USB) storage does not exist [CHAR LIMIT=25] -->
+ <string name="no_sdcard_title" product="nosdcard">Storage unavailable</string>
<!-- Dialog title shown when SD Card does not exist -->
<string name="no_sdcard_title" product="default">No SD card</string>
- <!-- Dialog message shown when USB storage does not exist [CHAR LIMIT=30] -->
- <string name="no_sdcard_message" product="nosdcard">No USB storage detected</string>
+ <!-- Dialog message shown when (USB) storage does not exist [CHAR LIMIT=30] -->
+ <string name="no_sdcard_message" product="nosdcard">No storage detected</string>
<!-- Dialog message shown when SDcard does not exist -->
<string name="no_sdcard_message" product="default">No SD card detected</string>
@@ -696,13 +705,13 @@
<!-- Action string for selecting SIM for importing contacts -->
<string name="import_from_sim">Import from SIM card</string>
- <!-- Action string for selecting USB storage for importing contacts [CHAR LIMIT=25] -->
- <string name="import_from_sdcard" product="nosdcard">Import from USB storage</string>
+ <!-- Action string for selecting (USB) storage for importing contacts [CHAR LIMIT=25] -->
+ <string name="import_from_sdcard" product="nosdcard">Import from storage</string>
<!-- Action string for selecting SD Card for importing contacts -->
<string name="import_from_sdcard" product="default">Import from SD card</string>
- <!-- Action that exports all contacts to USB storage [CHAR LIMIT=25] -->
- <string name="export_to_sdcard" product="nosdcard">Export to USB storage</string>
+ <!-- Action that exports all contacts to (USB) storage [CHAR LIMIT=25] -->
+ <string name="export_to_sdcard" product="nosdcard">Export to storage</string>
<!-- Action that exports all contacts to SD Card -->
<string name="export_to_sdcard" product="default">Export to SD card</string>
@@ -724,19 +733,19 @@
than one vCard files available in the system. -->
<string name="import_all_vcard_string">Import all vCard files</string>
- <!-- Dialog message shown when searching VCard data from SD Card [CHAR LIMIT=NONE] -->
- <string name="searching_vcard_message" product="nosdcard">Searching for vCard data in USB storage</string>
+ <!-- Dialog message shown when searching VCard data from (USB) storage [CHAR LIMIT=NONE] -->
+ <string name="searching_vcard_message" product="nosdcard">Searching for vCard data in storage</string>
<!-- Dialog message shown when searching VCard data from SD Card -->
<string name="searching_vcard_message" product="default">Searching for vCard data on SD card</string>
<!-- Dialog title shown when scanning VCard data failed. [CHAR LIMIT=NONE] -->
- <string name="scanning_sdcard_failed_title" product="nosdcard">Scanning USB storage failed</string>
+ <string name="scanning_sdcard_failed_title" product="nosdcard">Scanning storage failed</string>
<!-- Dialog title shown when scanning VCard data failed. -->
<string name="scanning_sdcard_failed_title" product="default">Scanning SD card failed</string>
<!-- Dialog message shown when searching VCard data failed.
An exact reason for the failure should [CHAR LIMIT=NONE] -->
- <string name="scanning_sdcard_failed_message" product="nosdcard">Scanning USB storage failed (Reason: \"<xliff:g id="fail_reason">%s</xliff:g>\")</string>
+ <string name="scanning_sdcard_failed_message" product="nosdcard">Scanning storage failed (Reason: \"<xliff:g id="fail_reason">%s</xliff:g>\")</string>
<!-- Dialog message shown when searching VCard data failed.
An exact reason for the failure should -->
<string name="scanning_sdcard_failed_message" product="default">Scanning SD card failed (Reason: \"<xliff:g id="fail_reason">%s</xliff:g>\")</string>
@@ -762,9 +771,9 @@
<string name="vcard_import_failed">Failed to import vCard</string>
<!-- The failure message shown when the system could not find any vCard file.
- (with extension ".vcf" in USB storage.)
+ (with extension ".vcf" in (USB) storage.)
[CHAR LIMIT=128] -->
- <string name="import_failure_no_vcard_file" product="nosdcard">No vCard file found in the USB storage</string>
+ <string name="import_failure_no_vcard_file" product="nosdcard">No vCard file found in the storage</string>
<!-- The failure message shown when the system could not find any vCard file.
(with extension ".vcf" in SDCard.)
[CHAR LIMIT=128] -->
@@ -864,7 +873,7 @@
<!-- The failed reason shown when vCard exporter could not create a file for the vCard since
there are too many files relevant to vCard. [CHAR LIMIT=NONE] -->
- <string name="fail_reason_too_many_vcard" product="nosdcard">Too many vCard files in the USB storage</string>
+ <string name="fail_reason_too_many_vcard" product="nosdcard">Too many vCard files in the storage</string>
<!-- The failed reason shown when vCard exporter could not create a file for the vCard since
there are too many files relevant to vCard. -->
<string name="fail_reason_too_many_vcard" product="default">Too many vCard files on the SD card</string>
@@ -1216,12 +1225,14 @@
<string name="name_phonetic_middle">Phonetic middle name</string>
<!-- Field title for the phonetic family name of a contact -->
<string name="name_phonetic_family">Phonetic family name</string>
+ <!-- Field title for the phonetic name of a contact [CHAR LIMIT=64]-->
+ <string name="name_phonetic">Phonetic name</string>
<!-- String describing which account type a contact came from when editing it -->
<string name="account_type_format"><xliff:g id="source" example="Gmail">%1$s</xliff:g> contact</string>
<!-- String describing which account a contact came from when editing it -->
- <string name="from_account_format">from <xliff:g id="source" example="user@gmail.com">%1$s</xliff:g></string>
+ <string name="from_account_format"><xliff:g id="source" example="user@gmail.com">%1$s</xliff:g></string>
<!-- Checkbox asking the user if they want to display a particular photo for a contact -->
<string name="use_photo_as_primary">Use this photo</string>
@@ -1314,6 +1325,30 @@
<!-- The add field button shown in the editor under each editable Raw Contact [CHAR LIMIT=30] -->
<string name="add_field">Add another field</string>
+ <!-- The editable field hint text to add a new phone number to a contact in the Raw Contact Editor [CHAR LIMIT=22] -->
+ <string name="add_phone">Add new phone number</string>
+
+ <!-- The editable field hint text to add a new email to a contact in the Raw Contact Editor [CHAR LIMIT=22] -->
+ <string name="add_email">Add new email</string>
+
+ <!-- The editable field hint text to add a new IM account to a contact in the Raw Contact Editor [CHAR LIMIT=22] -->
+ <string name="add_im">Add new IM account</string>
+
+ <!-- The editable field hint text to add a new postal address to a contact in the Raw Contact Editor [CHAR LIMIT=22] -->
+ <string name="add_address">Add new address</string>
+
+ <!-- The editable field hint text to add a new note to a contact in the Raw Contact Editor [CHAR LIMIT=22] -->
+ <string name="add_note">Add new note</string>
+
+ <!-- The editable field hint text to add a new website to a contact in the Raw Contact Editor [CHAR LIMIT=22] -->
+ <string name="add_website">Add new website</string>
+
+ <!-- The editable field hint text to add a new event to a contact in the Raw Contact Editor [CHAR LIMIT=22] -->
+ <string name="add_event">Add new event</string>
+
+ <!-- The editable field hint text to add a relationship field to a contact in the Raw Contact Editor [CHAR LIMIT=22] -->
+ <string name="add_relationship">Add new relationship</string>
+
<!-- Attbution 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>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index db50204..0582fd4 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -14,18 +14,37 @@
limitations under the License.
-->
<resources>
- <style name="DialtactsTheme" parent="@android:Theme">
- <item name="android:windowNoTitle">true</item>
+ <style name="DialtactsTheme" parent="android:Theme.Holo.Light">
<item name="android:windowContentOverlay">@null</item>
+ <item name="list_item_height">?android:attr/listPreferredItemHeight</item>
+ <item name="activated_background">@drawable/list_item_activated_background</item>
+ <item name="section_header_background">@drawable/list_title_holo</item>
+ <item name="list_section_header_height">32dip</item>
+ <item name="list_item_divider">@drawable/list_item_divider</item>
+ <item name="list_item_padding_top">4dip</item>
+ <item name="list_item_padding_right">11dip</item>
+ <item name="list_item_padding_bottom">4dip</item>
+ <item name="list_item_padding_left">4dip</item>
+ <item name="list_item_gap_between_image_and_text">8dip</item>
+ <item name="list_item_gap_between_label_and_data">5dip</item>
+ <item name="list_item_call_button_padding">14dip</item>
+ <item name="list_item_vertical_divider_margin">5dip</item>
+ <item name="list_item_presence_icon_margin">5dip</item>
+ <item name="list_item_photo_size">56dip</item>
+ <item name="list_item_prefix_highlight_color">#729a27</item>
+ <item name="list_item_header_text_indent">56dip</item>
+ <item name="list_item_header_text_color">?color/section_header_text_color</item>
+ <item name="list_item_header_text_size">14sp</item>
+ <item name="contact_filter_popup_width">320dip</item>
</style>
- <style name="CallDetailActivityTheme" parent="android:Theme.NoTitleBar">
+ <style name="CallDetailActivityTheme" parent="android:Theme.Holo.Light">
<item name="android:windowContentOverlay">@null</item>
</style>
- <style name="ContactDetailActivityTheme" parent="android:Theme.NoTitleBar">
+ <style name="ContactDetailActivityTheme" parent="android:Theme.Holo.Light">
<item name="android:windowContentOverlay">@null</item>
</style>
- <style name="ContactEditorActivityTheme" parent="android:Theme.NoTitleBar">
+ <style name="ContactEditorActivityTheme" parent="android:Theme.Holo.Light">
<item name="android:windowContentOverlay">@null</item>
</style>
@@ -38,38 +57,19 @@
<item name="android:windowIsFloating">true</item>
</style>
- <style name="FullyTranslucent" parent="android:Theme.Translucent.NoTitleBar">
- <item name="android:windowContentOverlay">@null</item>
+ <style name="Theme">
</style>
- <style name="FullyTranslucent.QuickContact">
- <!-- This is a hack because we want to be able to animate away the
- QuickContact window, and we close its containing activity at the
- same time. So put in a dummy animation so this guy sticks around
- while the fast track window is animating. -->
- <item name="android:windowAnimationStyle">@style/DummyAnimation</item>
- </style>
-
- <style name="QuickContact" parent="@android:Theme.Holo.Light">
- <item name="android:windowNoTitle">true</item>
- <item name="android:windowFrame">@null</item>
+ <style name="Theme.QuickContact" parent="@android:style/Theme.Holo.Light">
<item name="android:windowBackground">@android:color/transparent</item>
- <item name="android:windowIsFloating">true</item>
+ <item name="android:colorBackgroundCacheHint">@null</item>
+ <item name="android:windowFrame">@null</item>
<item name="android:windowContentOverlay">@null</item>
- <!-- TODO: create our own animation style in framework -->
- <!--
- <item name="android:windowAnimationStyle">@*android:style/Animation.ZoomButtons</item>
- -->
- </style>
-
- <style name="QuickContactAboveAnimation">
- <item name="android:windowEnterAnimation">@anim/quickcontact_above_enter</item>
- <item name="android:windowExitAnimation">@anim/quickcontact_above_exit</item>
- </style>
-
- <style name="QuickContactBelowAnimation">
- <item name="android:windowEnterAnimation">@anim/quickcontact_below_enter</item>
- <item name="android:windowExitAnimation">@anim/quickcontact_below_exit</item>
+ <item name="android:windowAnimationStyle">@null</item>
+ <item name="android:windowIsFloating">false</item>
+ <item name="android:backgroundDimEnabled">false</item>
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowNoTitle">true</item>
</style>
<style name="ContactsSearchAnimation">
@@ -110,7 +110,31 @@
<style name="ContactBrowserTheme" parent="@android:Theme">
<item name="list_item_height">?android:attr/listPreferredItemHeight</item>
<item name="activated_background">@drawable/list_item_activated_background</item>
- <item name="section_header_background">@drawable/section_header</item>
+ <item name="section_header_background">@drawable/list_title_holo</item>
+ <item name="list_section_header_height">32dip</item>
+ <item name="list_item_divider">@drawable/list_item_divider</item>
+ <item name="list_item_padding_top">4dip</item>
+ <item name="list_item_padding_right">11dip</item>
+ <item name="list_item_padding_bottom">4dip</item>
+ <item name="list_item_padding_left">4dip</item>
+ <item name="list_item_gap_between_image_and_text">8dip</item>
+ <item name="list_item_gap_between_label_and_data">5dip</item>
+ <item name="list_item_call_button_padding">14dip</item>
+ <item name="list_item_vertical_divider_margin">5dip</item>
+ <item name="list_item_presence_icon_margin">5dip</item>
+ <item name="list_item_photo_size">56dip</item>
+ <item name="list_item_prefix_highlight_color">#729a27</item>
+ <item name="list_item_header_text_indent">56dip</item>
+ <item name="list_item_header_text_color">?color/section_header_text_color</item>
+ <item name="list_item_header_text_size">14sp</item>
+ <item name="contact_filter_popup_width">320dip</item>
+ </style>
+
+ <!-- TODO: Clean up this file so themes aren't copied. -->
+ <style name="GroupDetailTheme" parent="@android:Theme">
+ <item name="list_item_height">?android:attr/listPreferredItemHeight</item>
+ <item name="activated_background">@drawable/list_item_activated_background</item>
+ <item name="section_header_background">@drawable/list_title_holo</item>
<item name="list_section_header_height">32dip</item>
<item name="list_item_divider">@drawable/list_item_divider</item>
<item name="list_item_padding_top">4dip</item>
@@ -152,7 +176,7 @@
<style name="JoinContactActivityTheme" parent="ContactPickerTheme" >
</style>
- <style name="ContactsPreferencesTheme" parent="@android:Theme">
+ <style name="ContactsPreferencesTheme" parent="@android:Theme.Holo.Light">
</style>
<style name="CustomContactListFilterTheme" parent="@android:Theme">
@@ -208,4 +232,15 @@
<item name="android:layout_height">2dip</item>
<item name="android:layout_width">match_parent</item>
</style>
+
+ <style name="ContactDetailItemType">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
+ <item name="android:textColor">@color/detail_item_type_color</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:paddingTop">5dip</item>
+ </style>
</resources>
diff --git a/src/com/android/contacts/CallContactActivity.java b/src/com/android/contacts/CallContactActivity.java
index 38e890d..77bf20c 100644
--- a/src/com/android/contacts/CallContactActivity.java
+++ b/src/com/android/contacts/CallContactActivity.java
@@ -44,7 +44,8 @@
finish();
}
- // If we are being invoked with a saved state, rely on Activity to restore it
+ // If this method is being invoked with a saved state, rely on Activity
+ // to restore it
if (savedInstanceState != null) {
return;
}
@@ -57,6 +58,7 @@
}
}
+ @Override
public void onDismiss(DialogInterface dialog) {
if (!isChangingConfigurations()) {
finish();
diff --git a/src/com/android/contacts/ContactLoader.java b/src/com/android/contacts/ContactLoader.java
index f4baf3b..4b0bbaa 100644
--- a/src/com/android/contacts/ContactLoader.java
+++ b/src/com/android/contacts/ContactLoader.java
@@ -93,6 +93,7 @@
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;
@@ -131,6 +132,7 @@
mPhotoId = -1;
mPhotoUri = null;
mDisplayName = null;
+ mAltDisplayName = null;
mPhoneticName = null;
mStarred = false;
mPresence = null;
@@ -145,8 +147,9 @@
*/
private Result(Uri uri, Uri lookupUri, long directoryId, String lookupKey, long id,
long nameRawContactId, int displayNameSource, long photoId, String photoUri,
- String displayName, String phoneticName, boolean starred, Integer presence,
- String status, Long statusTimestamp, Integer statusLabel, String statusResPackage) {
+ String displayName, String altDisplayName, String phoneticName, boolean starred,
+ Integer presence, String status, Long statusTimestamp, Integer statusLabel,
+ String statusResPackage) {
mLookupUri = lookupUri;
mUri = uri;
mDirectoryId = directoryId;
@@ -159,6 +162,7 @@
mPhotoId = photoId;
mPhotoUri = photoUri;
mDisplayName = displayName;
+ mAltDisplayName = altDisplayName;
mPhoneticName = phoneticName;
mStarred = starred;
mPresence = presence;
@@ -179,6 +183,7 @@
mPhotoId = from.mPhotoId;
mPhotoUri = from.mPhotoUri;
mDisplayName = from.mDisplayName;
+ mAltDisplayName = from.mAltDisplayName;
mPhoneticName = from.mPhoneticName;
mStarred = from.mStarred;
mPresence = from.mPresence;
@@ -257,6 +262,10 @@
return mDisplayName;
}
+ public String getAltDisplayName() {
+ return mAltDisplayName;
+ }
+
public String getPhoneticName() {
return mPhoneticName;
}
@@ -380,6 +389,7 @@
Contacts.DISPLAY_NAME_SOURCE,
Contacts.LOOKUP_KEY,
Contacts.DISPLAY_NAME,
+ Contacts.DISPLAY_NAME_ALTERNATIVE,
Contacts.PHONETIC_NAME,
Contacts.PHOTO_ID,
Contacts.STARRED,
@@ -447,67 +457,68 @@
public final static int DISPLAY_NAME_SOURCE = 1;
public final static int LOOKUP_KEY = 2;
public final static int DISPLAY_NAME = 3;
- public final static int PHONETIC_NAME = 4;
- public final static int PHOTO_ID = 5;
- public final static int STARRED = 6;
- public final static int CONTACT_PRESENCE = 7;
- public final static int CONTACT_STATUS = 8;
- public final static int CONTACT_STATUS_TIMESTAMP = 9;
- public final static int CONTACT_STATUS_RES_PACKAGE = 10;
- public final static int CONTACT_STATUS_LABEL = 11;
- public final static int CONTACT_ID = 12;
- public final static int RAW_CONTACT_ID = 13;
+ public final static int ALT_DISPLAY_NAME = 4;
+ public final static int PHONETIC_NAME = 5;
+ public final static int PHOTO_ID = 6;
+ public final static int STARRED = 7;
+ public final static int CONTACT_PRESENCE = 8;
+ public final static int CONTACT_STATUS = 9;
+ public final static int CONTACT_STATUS_TIMESTAMP = 10;
+ public final static int CONTACT_STATUS_RES_PACKAGE = 11;
+ public final static int CONTACT_STATUS_LABEL = 12;
+ public final static int CONTACT_ID = 13;
+ public final static int RAW_CONTACT_ID = 14;
- public final static int ACCOUNT_NAME = 14;
- public final static int ACCOUNT_TYPE = 15;
- public final static int DIRTY = 16;
- public final static int VERSION = 17;
- public final static int SOURCE_ID = 18;
- public final static int SYNC1 = 19;
- public final static int SYNC2 = 20;
- public final static int SYNC3 = 21;
- public final static int SYNC4 = 22;
- public final static int DELETED = 23;
- public final static int IS_RESTRICTED = 24;
- public final static int NAME_VERIFIED = 25;
+ public final static int ACCOUNT_NAME = 15;
+ public final static int ACCOUNT_TYPE = 16;
+ public final static int DIRTY = 17;
+ public final static int VERSION = 18;
+ public final static int SOURCE_ID = 19;
+ public final static int SYNC1 = 20;
+ public final static int SYNC2 = 21;
+ public final static int SYNC3 = 22;
+ public final static int SYNC4 = 23;
+ public final static int DELETED = 24;
+ public final static int IS_RESTRICTED = 25;
+ public final static int NAME_VERIFIED = 26;
- public final static int DATA_ID = 26;
- public final static int DATA1 = 27;
- public final static int DATA2 = 28;
- public final static int DATA3 = 29;
- public final static int DATA4 = 30;
- public final static int DATA5 = 31;
- public final static int DATA6 = 32;
- public final static int DATA7 = 33;
- public final static int DATA8 = 34;
- public final static int DATA9 = 35;
- public final static int DATA10 = 36;
- public final static int DATA11 = 37;
- public final static int DATA12 = 38;
- public final static int DATA13 = 39;
- public final static int DATA14 = 40;
- public final static int DATA15 = 41;
- public final static int DATA_SYNC1 = 42;
- public final static int DATA_SYNC2 = 43;
- public final static int DATA_SYNC3 = 44;
- public final static int DATA_SYNC4 = 45;
- public final static int DATA_VERSION = 46;
- public final static int IS_PRIMARY = 47;
- public final static int IS_SUPERPRIMARY = 48;
- public final static int MIMETYPE = 49;
- public final static int RES_PACKAGE = 50;
+ public final static int DATA_ID = 27;
+ public final static int DATA1 = 28;
+ public final static int DATA2 = 29;
+ public final static int DATA3 = 30;
+ public final static int DATA4 = 31;
+ public final static int DATA5 = 32;
+ public final static int DATA6 = 33;
+ public final static int DATA7 = 34;
+ public final static int DATA8 = 35;
+ public final static int DATA9 = 36;
+ public final static int DATA10 = 37;
+ public final static int DATA11 = 38;
+ public final static int DATA12 = 39;
+ public final static int DATA13 = 40;
+ public final static int DATA14 = 41;
+ public final static int DATA15 = 42;
+ public final static int DATA_SYNC1 = 43;
+ public final static int DATA_SYNC2 = 44;
+ public final static int DATA_SYNC3 = 45;
+ public final static int DATA_SYNC4 = 46;
+ public final static int DATA_VERSION = 47;
+ public final static int IS_PRIMARY = 48;
+ public final static int IS_SUPERPRIMARY = 49;
+ public final static int MIMETYPE = 50;
+ public final static int RES_PACKAGE = 51;
- public final static int GROUP_SOURCE_ID = 51;
+ public final static int GROUP_SOURCE_ID = 52;
- public final static int PRESENCE = 52;
- public final static int CHAT_CAPABILITY = 53;
- public final static int STATUS = 54;
- public final static int STATUS_RES_PACKAGE = 55;
- public final static int STATUS_ICON = 56;
- public final static int STATUS_LABEL = 57;
- public final static int STATUS_TIMESTAMP = 58;
+ public final static int PRESENCE = 53;
+ public final static int CHAT_CAPABILITY = 54;
+ public final static int STATUS = 55;
+ public final static int STATUS_RES_PACKAGE = 56;
+ public final static int STATUS_ICON = 57;
+ public final static int STATUS_LABEL = 58;
+ public final static int STATUS_TIMESTAMP = 59;
- public final static int PHOTO_URI = 59;
+ public final static int PHOTO_URI = 60;
}
private static class DirectoryQuery {
@@ -699,6 +710,7 @@
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);
@@ -726,8 +738,8 @@
return new Result(contactUri, lookupUri, directoryId, lookupKey, contactId,
nameRawContactId, displayNameSource, photoId, photoUri, displayName,
- phoneticName, starred, presence, status, statusTimestamp, statusLabel,
- statusResPackage);
+ altDisplayName, phoneticName, starred, presence, status, statusTimestamp,
+ statusLabel, statusResPackage);
}
/**
diff --git a/src/com/android/contacts/ContactPhotoManager.java b/src/com/android/contacts/ContactPhotoManager.java
new file mode 100644
index 0000000..150856a
--- /dev/null
+++ b/src/com/android/contacts/ContactPhotoManager.java
@@ -0,0 +1,747 @@
+/*
+ * 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;
+
+import com.android.contacts.model.AccountTypeManager;
+import com.google.android.collect.Lists;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+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.util.Log;
+import android.util.LruCache;
+import android.widget.ImageView;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.lang.ref.SoftReference;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Asynchronously loads contact photos and maintains a cache of photos.
+ */
+public abstract class ContactPhotoManager {
+
+ static final String TAG = "ContactPhotoManager";
+
+ public static final String CONTACT_PHOTO_SERVICE = "contactPhotos";
+
+ /**
+ * The resource ID of the image to be used when the photo is unavailable or being
+ * loaded.
+ */
+ protected final int mDefaultResourceId = R.drawable.ic_contact_picture;
+
+ /**
+ * 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 ContactPhotoManager getInstance(Context context) {
+ ContactPhotoManager service =
+ (ContactPhotoManager) context.getSystemService(CONTACT_PHOTO_SERVICE);
+ if (service == null) {
+ service = createContactPhotoManager(context);
+ Log.e(TAG, "No contact photo service in context: " + context);
+ }
+ return service;
+ }
+
+ public static synchronized ContactPhotoManager createContactPhotoManager(Context context) {
+ return new ContactPhotoManagerImpl(context);
+ }
+
+ /**
+ * 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 database.
+ */
+ public abstract void loadPhoto(ImageView view, long photoId);
+
+ /**
+ * 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.
+ */
+ public abstract void loadPhoto(ImageView view, Uri photoUri);
+
+ /**
+ * 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();
+
+ /**
+ * Initiates a background process that over time will fill up cache with
+ * preload photos.
+ */
+ public abstract void preloadPhotosInBackground();
+}
+
+class ContactPhotoManagerImpl extends ContactPhotoManager implements Callback {
+ private static final String LOADER_THREAD_NAME = "ContactPhotoLoader";
+
+ /**
+ * 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 };
+
+ /**
+ * Maintains the state of a particular photo.
+ */
+ private static class BitmapHolder {
+ final byte[] bytes;
+
+ volatile boolean fresh;
+ Bitmap bitmap;
+ SoftReference<Bitmap> bitmapRef;
+
+ public BitmapHolder(byte[] bytes) {
+ this.bytes = bytes;
+ this.fresh = true;
+ }
+ }
+
+ 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;
+
+ /**
+ * 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. Please note that this
+ * photo ID may change before the photo loading request is started.
+ */
+ private final ConcurrentHashMap<ImageView, Object> mPendingRequests =
+ new ConcurrentHashMap<ImageView, Object>();
+
+ /**
+ * 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;
+
+ public ContactPhotoManagerImpl(Context context) {
+ mContext = context;
+
+ Resources resources = context.getResources();
+ mBitmapCache = new LruCache<Object, Bitmap>(
+ resources.getInteger(R.integer.config_photo_cache_max_bitmaps));
+ int maxBytes = resources.getInteger(R.integer.config_photo_cache_max_bytes);
+ mBitmapHolderCache = new LruCache<Object, BitmapHolder>(maxBytes) {
+ @Override protected int sizeOf(Object key, BitmapHolder value) {
+ return value.bytes != null ? value.bytes.length : 0;
+ }
+ };
+ mBitmapHolderCacheRedZoneBytes = (int) (maxBytes * 0.75);
+ }
+
+ @Override
+ public void preloadPhotosInBackground() {
+ ensureLoaderThread();
+ mLoaderThread.requestPreloading();
+ }
+
+ @Override
+ public void loadPhoto(ImageView view, long photoId) {
+ if (photoId == 0) {
+ // No photo is needed
+ view.setImageResource(mDefaultResourceId);
+ mPendingRequests.remove(view);
+ } else {
+ loadPhotoByIdOrUri(view, photoId);
+ }
+ }
+
+ @Override
+ public void loadPhoto(ImageView view, Uri photoUri) {
+ if (photoUri == null) {
+ // No photo is needed
+ view.setImageResource(mDefaultResourceId);
+ mPendingRequests.remove(view);
+ } else {
+ loadPhotoByIdOrUri(view, photoUri);
+ }
+ }
+
+ private void loadPhotoByIdOrUri(ImageView view, Object key) {
+ boolean loaded = loadCachedPhoto(view, key);
+ if (loaded) {
+ mPendingRequests.remove(view);
+ } else {
+ mPendingRequests.put(view, key);
+ if (!mPaused) {
+ // Send a request to start loading photos
+ requestLoading();
+ }
+ }
+ }
+
+ @Override
+ public void refreshCache() {
+ for (BitmapHolder holder : mBitmapHolderCache.snapshot().values()) {
+ 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, Object key) {
+ BitmapHolder holder = mBitmapHolderCache.get(key);
+ if (holder == null) {
+ // The bitmap has not been loaded - should display the placeholder image.
+ view.setImageResource(mDefaultResourceId);
+ return false;
+ }
+
+ if (holder.bytes == null) {
+ view.setImageResource(mDefaultResourceId);
+ return holder.fresh;
+ }
+
+ // Optionally decode bytes into a bitmap
+ inflateBitmap(holder);
+
+ view.setImageBitmap(holder.bitmap);
+
+ // Put the bitmap in the LRU cache
+ mBitmapCache.put(key, holder.bitmap);
+
+ // Soften the reference
+ holder.bitmap = null;
+
+ return holder.fresh;
+ }
+
+ /**
+ * 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 void inflateBitmap(BitmapHolder holder) {
+ byte[] bytes = holder.bytes;
+ if (bytes == null || bytes.length == 0) {
+ return;
+ }
+
+ // 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 = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, null);
+ holder.bitmap = bitmap;
+ holder.bitmapRef = new SoftReference<Bitmap>(bitmap);
+ } catch (OutOfMemoryError e) {
+ // Do nothing - the photo will appear to be missing
+ }
+ }
+
+ public void clear() {
+ mPendingRequests.clear();
+ mBitmapHolderCache.evictAll();
+ }
+
+ @Override
+ public void pause() {
+ mPaused = true;
+ }
+
+ @Override
+ public void resume() {
+ mPaused = false;
+ 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.
+ */
+ 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();
+ }
+ 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() {
+ Iterator<ImageView> iterator = mPendingRequests.keySet().iterator();
+ while (iterator.hasNext()) {
+ ImageView view = iterator.next();
+ Object key = mPendingRequests.get(view);
+ boolean loaded = loadCachedPhoto(view, key);
+ 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) {
+ BitmapHolder holder = new BitmapHolder(bytes);
+ holder.fresh = true;
+
+ // Unless this image is being preloaded, decode it right away while
+ // we are still on the background thread.
+ if (!preloading) {
+ inflateBitmap(holder);
+ }
+
+ mBitmapHolderCache.put(key, holder);
+ }
+
+ /**
+ * Populates an array of photo IDs that need to be loaded.
+ */
+ private void obtainPhotoIdsAndUrisToLoad(ArrayList<Long> photoIds,
+ ArrayList<String> photoIdsAsStrings, ArrayList<Uri> uris) {
+ photoIds.clear();
+ photoIdsAsStrings.clear();
+ uris.clear();
+
+ /*
+ * 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<Object> iterator = mPendingRequests.values().iterator();
+ while (iterator.hasNext()) {
+ Object key = iterator.next();
+ BitmapHolder holder = mBitmapHolderCache.get(key);
+ if (holder == null || !holder.fresh) {
+ if (key instanceof Long) {
+ photoIds.add((Long)key);
+ photoIdsAsStrings.add(key.toString());
+ } else {
+ uris.add((Uri)key);
+ }
+ }
+ }
+ }
+
+ /**
+ * 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 = 50;
+
+ /**
+ * 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 = 500;
+
+ private final ContentResolver mResolver;
+ private final StringBuilder mStringBuilder = new StringBuilder();
+ private final ArrayList<Long> mPhotoIds = Lists.newArrayList();
+ private final ArrayList<String> mPhotoIdsAsStrings = Lists.newArrayList();
+ private final ArrayList<Uri> mPhotoUris = Lists.newArrayList();
+ private ArrayList<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.
+ */
+ 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);
+ }
+
+ loadPhotosFromDatabase(false);
+
+ if (preloadSize == 0) {
+ mPreloadStatus = PRELOAD_STATUS_DONE;
+ }
+
+ Log.v(TAG, "Preloaded " + count + " photos. Photos in cache: "
+ + mBitmapHolderCache.size()
+ + ". Total size: " + 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() {
+ obtainPhotoIdsAndUrisToLoad(mPhotoIds, mPhotoIdsAsStrings, mPhotoUris);
+ loadPhotosFromDatabase(true);
+ loadRemotePhotos();
+ requestPreloading();
+ }
+
+ private void loadPhotosFromDatabase(boolean preloading) {
+ int count = mPhotoIds.size();
+ if (count == 0) {
+ 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 (int i = 0; i < count; i++) {
+ mPreloadPhotoIds.remove(mPhotoIds.get(i));
+ }
+ if (mPreloadPhotoIds.isEmpty()) {
+ mPreloadStatus = PRELOAD_STATUS_DONE;
+ }
+ }
+
+ mStringBuilder.setLength(0);
+ mStringBuilder.append(Photo._ID + " IN(");
+ for (int i = 0; i < count; i++) {
+ if (i != 0) {
+ mStringBuilder.append(',');
+ }
+ mStringBuilder.append('?');
+ }
+ mStringBuilder.append(')');
+
+ Cursor cursor = null;
+ try {
+ 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);
+ mPhotoIds.remove(id);
+ }
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+
+ // Remaining photos were not found in the database - mark the cache accordingly.
+ count = mPhotoIds.size();
+ for (int i = 0; i < count; i++) {
+ cacheBitmap(mPhotoIds.get(i), null, preloading);
+ }
+
+ mMainThreadHandler.sendEmptyMessage(MESSAGE_PHOTOS_LOADED);
+ }
+
+ private void loadRemotePhotos() {
+ int count = mPhotoUris.size();
+ for (int i = 0; i < count; i++) {
+ Uri uri = mPhotoUris.get(i);
+ if (mBuffer == null) {
+ mBuffer = new byte[BUFFER_SIZE];
+ }
+ try {
+ InputStream 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(uri, baos.toByteArray(), false);
+ mMainThreadHandler.sendEmptyMessage(MESSAGE_PHOTOS_LOADED);
+ } else {
+ Log.v(TAG, "Cannot load photo " + uri);
+ cacheBitmap(uri, null, false);
+ }
+ } catch (Exception ex) {
+ Log.v(TAG, "Cannot load photo " + uri, ex);
+ cacheBitmap(uri, null, false);
+ }
+ }
+ }
+ }
+}
diff --git a/src/com/android/contacts/ContactSaveService.java b/src/com/android/contacts/ContactSaveService.java
index c07dd68..9b56f5b 100644
--- a/src/com/android/contacts/ContactSaveService.java
+++ b/src/com/android/contacts/ContactSaveService.java
@@ -16,11 +16,14 @@
package com.android.contacts;
-import com.android.contacts.R;
+import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.EntityDeltaList;
+import com.android.contacts.model.EntityModifier;
import com.google.android.collect.Lists;
import com.google.android.collect.Sets;
import android.accounts.Account;
+import android.app.Activity;
import android.app.IntentService;
import android.content.ContentProviderOperation;
import android.content.ContentProviderOperation.Builder;
@@ -35,6 +38,7 @@
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.provider.ContactsContract.AggregationExceptions;
@@ -48,6 +52,7 @@
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
/**
@@ -63,7 +68,9 @@
public static final String EXTRA_CONTENT_VALUES = "contentValues";
public static final String EXTRA_CALLBACK_INTENT = "callbackIntent";
- public static final String EXTRA_OPERATIONS = "Operations";
+ public static final String ACTION_SAVE_CONTACT = "saveContact";
+ public static final String EXTRA_CONTACT_STATE = "state";
+ public static final String EXTRA_SAVE_MODE = "saveMode";
public static final String ACTION_CREATE_GROUP = "createGroup";
public static final String ACTION_RENAME_GROUP = "renameGroup";
@@ -105,9 +112,46 @@
Data.DATA15
);
+ private static final int PERSIST_TRIES = 3;
+
+ public interface Listener {
+ public void onServiceCompleted(Intent callbackIntent);
+ }
+
+ private static final LinkedList<Listener> sListeners = new LinkedList<Listener>();
+
+ private Handler mMainHandler;
+
public ContactSaveService() {
super(TAG);
setIntentRedelivery(true);
+ mMainHandler = new Handler(Looper.getMainLooper());
+ }
+
+ public static void registerListener(Listener listener) {
+ if (!(listener instanceof Activity)) {
+ throw new ClassCastException("Only activities can be registered to"
+ + " receive callback from " + ContactSaveService.class.getName());
+ }
+ synchronized (sListeners) {
+ sListeners.addFirst(listener);
+ }
+ }
+
+ public static void unregisterListener(Listener listener) {
+ synchronized (sListeners) {
+ sListeners.remove(listener);
+ }
+ }
+
+ @Override
+ public Object getSystemService(String name) {
+ Object service = super.getSystemService(name);
+ if (service != null) {
+ return service;
+ }
+
+ return getApplicationContext().getSystemService(name);
}
@Override
@@ -115,6 +159,8 @@
String action = intent.getAction();
if (ACTION_NEW_RAW_CONTACT.equals(action)) {
createRawContact(intent);
+ } else if (ACTION_SAVE_CONTACT.equals(action)) {
+ saveContact(intent);
} else if (ACTION_CREATE_GROUP.equals(action)) {
createGroup(intent);
} else if (ACTION_RENAME_GROUP.equals(action)) {
@@ -156,8 +202,6 @@
// the callback intent.
Intent callbackIntent = new Intent(context, callbackActivity);
callbackIntent.setAction(callbackAction);
- callbackIntent.setFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
serviceIntent.putExtra(ContactSaveService.EXTRA_CALLBACK_INTENT, callbackIntent);
return serviceIntent;
}
@@ -195,7 +239,120 @@
Uri rawContactUri = results[0].uri;
callbackIntent.setData(RawContacts.getContactLookupUri(resolver, rawContactUri));
- startActivity(callbackIntent);
+ deliverCallback(callbackIntent);
+ }
+
+ /**
+ * Creates an intent that can be sent to this service to create a new raw contact
+ * using data presented as a set of ContentValues.
+ */
+ public static Intent createSaveContactIntent(Context context, EntityDeltaList state,
+ String saveModeExtraKey, int saveMode, Class<?> callbackActivity,
+ String callbackAction) {
+ Intent serviceIntent = new Intent(
+ context, ContactSaveService.class);
+ serviceIntent.setAction(ContactSaveService.ACTION_SAVE_CONTACT);
+ serviceIntent.putExtra(EXTRA_CONTACT_STATE, (Parcelable) state);
+
+ // Callback intent will be invoked by the service once the contact is
+ // saved. The service will put the URI of the new contact as "data" on
+ // the callback intent.
+ Intent callbackIntent = new Intent(context, callbackActivity);
+ callbackIntent.putExtra(saveModeExtraKey, saveMode);
+ callbackIntent.setAction(callbackAction);
+ serviceIntent.putExtra(ContactSaveService.EXTRA_CALLBACK_INTENT, callbackIntent);
+ return serviceIntent;
+ }
+
+ private void saveContact(Intent intent) {
+ EntityDeltaList state = intent.getParcelableExtra(EXTRA_CONTACT_STATE);
+ Intent callbackIntent = intent.getParcelableExtra(EXTRA_CALLBACK_INTENT);
+
+ // Trim any empty fields, and RawContacts, before persisting
+ final AccountTypeManager accountTypes = AccountTypeManager.getInstance(this);
+ EntityModifier.trimEmpty(state, accountTypes);
+
+ Uri lookupUri = null;
+
+ final ContentResolver resolver = getContentResolver();
+
+ // Attempt to persist changes
+ int tries = 0;
+ while (tries++ < PERSIST_TRIES) {
+ try {
+ // Build operations and try applying
+ final ArrayList<ContentProviderOperation> diff = state.buildDiff();
+ ContentProviderResult[] results = null;
+ if (!diff.isEmpty()) {
+ results = resolver.applyBatch(ContactsContract.AUTHORITY, diff);
+ }
+
+ final long rawContactId = getRawContactId(state, diff, results);
+ if (rawContactId == -1) {
+ throw new IllegalStateException("Could not determine RawContact ID after save");
+ }
+ final Uri rawContactUri = ContentUris.withAppendedId(
+ RawContacts.CONTENT_URI, rawContactId);
+ lookupUri = RawContacts.getContactLookupUri(resolver, rawContactUri);
+ Log.v(TAG, "Saved contact. New URI: " + lookupUri);
+ break;
+
+ } catch (RemoteException e) {
+ // Something went wrong, bail without success
+ Log.e(TAG, "Problem persisting user edits", e);
+ break;
+
+ } catch (OperationApplicationException e) {
+ // Version consistency failed, re-parent change and try again
+ Log.w(TAG, "Version consistency failed, re-parenting: " + e.toString());
+ final StringBuilder sb = new StringBuilder(RawContacts._ID + " IN(");
+ boolean first = true;
+ final int count = state.size();
+ for (int i = 0; i < count; i++) {
+ Long rawContactId = state.getRawContactId(i);
+ if (rawContactId != null && rawContactId != -1) {
+ if (!first) {
+ sb.append(',');
+ }
+ sb.append(rawContactId);
+ first = false;
+ }
+ }
+ sb.append(")");
+
+ if (first) {
+ throw new IllegalStateException("Version consistency failed for a new contact");
+ }
+
+ final EntityDeltaList newState = EntityDeltaList.fromQuery(resolver,
+ sb.toString(), null, null);
+ state = EntityDeltaList.mergeAfter(newState, state);
+ }
+ }
+
+ callbackIntent.setData(lookupUri);
+
+ deliverCallback(callbackIntent);
+ }
+
+ private long getRawContactId(EntityDeltaList state,
+ final ArrayList<ContentProviderOperation> diff,
+ final ContentProviderResult[] results) {
+ long rawContactId = state.findRawContactId();
+ if (rawContactId != -1) {
+ return rawContactId;
+ }
+
+ final int diffSize = diff.size();
+ for (int i = 0; i < diffSize; i++) {
+ ContentProviderOperation operation = diff.get(i);
+ if (operation.getType() == ContentProviderOperation.TYPE_INSERT
+ && operation.getUri().getEncodedPath().contains(
+ RawContacts.CONTENT_URI.getEncodedPath())) {
+ return ContentUris.parseId(results[i].uri);
+ }
+ }
+ return -1;
}
/**
@@ -214,8 +371,6 @@
// of the callback intent.
Intent callbackIntent = new Intent(context, callbackActivity);
callbackIntent.setAction(callbackAction);
- callbackIntent.setFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
serviceIntent.putExtra(ContactSaveService.EXTRA_CALLBACK_INTENT, callbackIntent);
return serviceIntent;
@@ -243,7 +398,7 @@
Intent callbackIntent = intent.getParcelableExtra(EXTRA_CALLBACK_INTENT);
callbackIntent.putExtra(ContactsContract.Intents.Insert.DATA, Lists.newArrayList(values));
- startActivity(callbackIntent);
+ deliverCallback(callbackIntent);
}
/**
@@ -407,8 +562,6 @@
// Callback intent will be invoked by the service once the contacts are joined.
Intent callbackIntent = new Intent(context, callbackActivity);
callbackIntent.setAction(callbackAction);
- callbackIntent.setFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
serviceIntent.putExtra(ContactSaveService.EXTRA_CALLBACK_INTENT, callbackIntent);
return serviceIntent;
@@ -523,7 +676,7 @@
ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactIds[0]));
callbackIntent.setData(uri);
}
- startActivity(callbackIntent);
+ deliverCallback(callbackIntent);
}
/**
@@ -543,7 +696,7 @@
* Shows a toast on the UI thread.
*/
private void showToast(final int message) {
- new Handler(Looper.getMainLooper()).post(new Runnable() {
+ mMainHandler.post(new Runnable() {
@Override
public void run() {
@@ -551,4 +704,29 @@
}
});
}
+
+ private void deliverCallback(final Intent callbackIntent) {
+ mMainHandler.post(new Runnable() {
+
+ @Override
+ public void run() {
+ deliverCallbackOnUiThread(callbackIntent);
+ }
+ });
+ }
+
+ void deliverCallbackOnUiThread(final Intent callbackIntent) {
+ // TODO: this assumes that if there are multiple instances of the same
+ // activity registered, the last one registered is the one waiting for
+ // the callback. Validity of this assumption needs to be verified.
+ synchronized (sListeners) {
+ for (Listener listener : sListeners) {
+ if (callbackIntent.getComponent().equals(
+ ((Activity) listener).getIntent().getComponent())) {
+ listener.onServiceCompleted(callbackIntent);
+ return;
+ }
+ }
+ }
+ }
}
diff --git a/src/com/android/contacts/ContactsActivity.java b/src/com/android/contacts/ContactsActivity.java
index 79ebecb..b78fad2 100644
--- a/src/com/android/contacts/ContactsActivity.java
+++ b/src/com/android/contacts/ContactsActivity.java
@@ -20,12 +20,16 @@
import android.app.Activity;
import android.content.ContentResolver;
+import android.content.Intent;
import android.content.SharedPreferences;
+import android.os.Bundle;
/**
* A common superclass for Contacts activities that handles application-wide services.
*/
-public abstract class ContactsActivity extends Activity {
+public abstract class ContactsActivity extends Activity
+ implements ContactSaveService.Listener
+{
private ContentResolver mContentResolver;
@@ -65,4 +69,21 @@
return getApplicationContext().getSystemService(name);
}
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ ContactSaveService.registerListener(this);
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onDestroy() {
+ ContactSaveService.unregisterListener(this);
+ super.onDestroy();
+ }
+
+ @Override
+ public void onServiceCompleted(Intent callbackIntent) {
+ onNewIntent(callbackIntent);
+ }
}
diff --git a/src/com/android/contacts/ContactsApplication.java b/src/com/android/contacts/ContactsApplication.java
index 8346c04..c925ec0 100644
--- a/src/com/android/contacts/ContactsApplication.java
+++ b/src/com/android/contacts/ContactsApplication.java
@@ -31,6 +31,7 @@
private static InjectedServices sInjectedServices;
private AccountTypeManager mAccountTypeManager;
+ private ContactPhotoManager mContactPhotoManager;
/**
* Overrides the system services with mocks for testing.
@@ -82,6 +83,14 @@
return mAccountTypeManager;
}
+ if (ContactPhotoManager.CONTACT_PHOTO_SERVICE.equals(name)) {
+ if (mContactPhotoManager == null) {
+ mContactPhotoManager = ContactPhotoManager.createContactPhotoManager(this);
+ mContactPhotoManager.preloadPhotosInBackground();
+ }
+ return mContactPhotoManager;
+ }
+
return super.getSystemService(name);
}
diff --git a/src/com/android/contacts/ContactsUtils.java b/src/com/android/contacts/ContactsUtils.java
index 0e75a7f..76cbc7d 100644
--- a/src/com/android/contacts/ContactsUtils.java
+++ b/src/com/android/contacts/ContactsUtils.java
@@ -16,6 +16,11 @@
package com.android.contacts;
+import com.google.i18n.phonenumbers.NumberParseException;
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import com.google.i18n.phonenumbers.PhoneNumberUtil.MatchType;
+import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
+
import android.content.Context;
import android.content.Intent;
import android.location.CountryDetector;
@@ -114,9 +119,19 @@
if (dataParts1.length != dataParts2.length) {
return false;
}
+ PhoneNumberUtil util = PhoneNumberUtil.getInstance();
for (int i = 0; i < dataParts1.length; i++) {
- if (!PhoneNumberUtils.compare(context, dataParts1[i], dataParts2[i])) {
- return false;
+ try {
+ PhoneNumber phoneNumber1 = util.parse(dataParts1[i], "ZZ" /* Unknown */);
+ PhoneNumber phoneNumber2 = util.parse(dataParts2[i], "ZZ" /* Unknown */);
+ MatchType matchType = util.isNumberMatch(phoneNumber1, phoneNumber2);
+ if (matchType != MatchType.SHORT_NSN_MATCH) {
+ return false;
+ }
+ } catch (NumberParseException e) {
+ if (!TextUtils.equals(dataParts1[i], dataParts2[i])) {
+ return false;
+ }
}
}
diff --git a/src/com/android/contacts/DialtactsActivity.java b/src/com/android/contacts/DialtactsActivity.java
deleted file mode 100644
index dc69194..0000000
--- a/src/com/android/contacts/DialtactsActivity.java
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.contacts;
-
-import com.android.contacts.activities.ContactsFrontDoor;
-import com.android.contacts.activities.ContactBrowserActivity;
-import com.android.internal.telephony.ITelephony;
-
-import android.app.Activity;
-import android.app.TabActivity;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.provider.CallLog.Calls;
-import android.provider.ContactsContract.Intents.UI;
-import android.util.Log;
-import android.view.Window;
-import android.widget.TabHost;
-
-/**
- * The dialer activity that has one tab with the virtual 12key
- * dialer, a tab with recent calls in it, a tab with the contacts and
- * a tab with the favorite. This is the container and the tabs are
- * embedded using intents.
- * The dialer tab's title is 'phone', a more common name (see strings.xml).
- */
-public class DialtactsActivity extends TabActivity implements TabHost.OnTabChangeListener {
- private static final String TAG = "Dailtacts";
-
- private static final int TAB_INDEX_DIALER = 0;
- private static final int TAB_INDEX_CALL_LOG = 1;
- private static final int TAB_INDEX_CONTACTS = 2;
- private static final int TAB_INDEX_FAVORITES = 3;
-
- static final String EXTRA_IGNORE_STATE = "ignore-state";
-
- /** Name of the dialtacts shared preferences */
- static final String PREFS_DIALTACTS = "dialtacts";
- /** If true, when handling the contacts intent the favorites tab will be shown instead */
- static final String PREF_FAVORITES_AS_CONTACTS = "favorites_as_contacts";
- static final boolean PREF_FAVORITES_AS_CONTACTS_DEFAULT = false;
-
- /** Last manually selected tab index */
- private static final String PREF_LAST_MANUALLY_SELECTED_TAB = "last_manually_selected_tab";
- private static final int PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT = TAB_INDEX_DIALER;
-
- private TabHost mTabHost;
- private String mFilterText;
- private Uri mDialUri;
-
- /**
- * The index of the tab that has last been manually selected (the user clicked on a tab).
- * This value does not keep track of programmatically set Tabs (e.g. Call Log after a Call)
- */
- private int mLastManuallySelectedTab;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- final Intent intent = getIntent();
- fixIntent(intent);
-
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.dialer_activity);
-
- mTabHost = getTabHost();
- mTabHost.setOnTabChangedListener(this);
-
- // Setup the tabs
- setupDialerTab();
- setupCallLogTab();
- setupContactsTab();
- setupFavoritesTab();
-
- // Load the last manually loaded tab
- final SharedPreferences prefs = getSharedPreferences(PREFS_DIALTACTS, MODE_PRIVATE);
- mLastManuallySelectedTab = prefs.getInt(PREF_LAST_MANUALLY_SELECTED_TAB,
- PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT);
-
- setCurrentTab(intent);
-
- if (UI.FILTER_CONTACTS_ACTION.equals(intent.getAction())
- && icicle == null) {
- setupFilterText(intent);
- }
- }
-
- @Override
- protected void onPause() {
- super.onPause();
-
- final int currentTabIndex = mTabHost.getCurrentTab();
- final SharedPreferences.Editor editor =
- getSharedPreferences(PREFS_DIALTACTS, MODE_PRIVATE).edit();
- if (currentTabIndex == TAB_INDEX_CONTACTS || currentTabIndex == TAB_INDEX_FAVORITES) {
- editor.putBoolean(PREF_FAVORITES_AS_CONTACTS, currentTabIndex == TAB_INDEX_FAVORITES);
- }
- editor.putInt(PREF_LAST_MANUALLY_SELECTED_TAB, mLastManuallySelectedTab);
-
- editor.apply();
- }
-
- private void fixIntent(Intent intent) {
- // This should be cleaned up: the call key used to send an Intent
- // that just said to go to the recent calls list. It now sends this
- // abstract action, but this class hasn't been rewritten to deal with it.
- if (Intent.ACTION_CALL_BUTTON.equals(intent.getAction())) {
- intent.setDataAndType(Calls.CONTENT_URI, Calls.CONTENT_TYPE);
- intent.putExtra("call_key", true);
- setIntent(intent);
- }
- }
-
- private void setupCallLogTab() {
- // Force the class since overriding tab entries doesn't work
- Intent intent = new Intent("com.android.phone.action.RECENT_CALLS");
- intent.setClass(this, RecentCallsListActivity.class);
-
- mTabHost.addTab(mTabHost.newTabSpec("call_log")
- .setIndicator(getString(R.string.recentCallsIconLabel),
- getResources().getDrawable(R.drawable.ic_tab_recent))
- .setContent(intent));
- }
-
- private void setupDialerTab() {
- Intent intent = new Intent("com.android.phone.action.TOUCH_DIALER");
- intent.setClass(this, TwelveKeyDialer.class);
-
- mTabHost.addTab(mTabHost.newTabSpec("dialer")
- .setIndicator(getString(R.string.dialerIconLabel),
- getResources().getDrawable(R.drawable.ic_tab_dialer))
- .setContent(intent));
- }
-
- private void setupContactsTab() {
- Intent intent = new Intent(UI.LIST_DEFAULT);
- intent.setClass(this, ContactBrowserActivity.class);
-
- mTabHost.addTab(mTabHost.newTabSpec("contacts")
- .setIndicator(getText(R.string.contactsIconLabel),
- getResources().getDrawable(R.drawable.ic_tab_contacts))
- .setContent(intent));
- }
-
- private void setupFavoritesTab() {
- Intent intent = new Intent(UI.LIST_STREQUENT_ACTION);
- intent.setClass(this, ContactBrowserActivity.class);
-
- mTabHost.addTab(mTabHost.newTabSpec("favorites")
- .setIndicator(getString(R.string.contactsFavoritesLabel),
- getResources().getDrawable(R.drawable.ic_tab_starred))
- .setContent(intent));
- }
-
- /**
- * Returns true if the intent is due to hitting the green send key while in a call.
- *
- * @param intent the intent that launched this activity
- * @param recentCallsRequest true if the intent is requesting to view recent calls
- * @return true if the intent is due to hitting the green send key while in a call
- */
- private boolean isSendKeyWhileInCall(final Intent intent, final boolean recentCallsRequest) {
- // If there is a call in progress go to the call screen
- if (recentCallsRequest) {
- final boolean callKey = intent.getBooleanExtra("call_key", false);
-
- try {
- ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
- if (callKey && phone != null && phone.showCallScreen()) {
- return true;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to handle send while in call", e);
- }
- }
-
- return false;
- }
-
- /**
- * Sets the current tab based on the intent's request type
- *
- * @param intent Intent that contains information about which tab should be selected
- */
- private void setCurrentTab(Intent intent) {
- // If we got here by hitting send and we're in call forward along to the in-call activity
- final boolean recentCallsRequest = Calls.CONTENT_TYPE.equals(intent.getType());
- if (isSendKeyWhileInCall(intent, recentCallsRequest)) {
- finish();
- return;
- }
-
- // Dismiss menu provided by any children activities
- Activity activity = getLocalActivityManager().
- getActivity(mTabHost.getCurrentTabTag());
- if (activity != null) {
- activity.closeOptionsMenu();
- }
-
- // Tell the children activities that they should ignore any possible saved
- // state and instead reload their state from the parent's intent
- intent.putExtra(EXTRA_IGNORE_STATE, true);
-
- // Remember the old manually selected tab index so that it can be restored if it is
- // overwritten by one of the programmatic tab selections
- final int savedTabIndex = mLastManuallySelectedTab;
-
- // Choose the tab based on the inbound intent
- if (intent.getBooleanExtra(ContactsFrontDoor.EXTRA_FRONT_DOOR, false)) {
- // Launched through the contacts front door, set the proper contacts tab (sticky
- // between favorites and contacts)
- SharedPreferences prefs = getSharedPreferences(PREFS_DIALTACTS, MODE_PRIVATE);
- boolean favoritesAsContacts = prefs.getBoolean(PREF_FAVORITES_AS_CONTACTS,
- PREF_FAVORITES_AS_CONTACTS_DEFAULT);
- if (favoritesAsContacts) {
- mTabHost.setCurrentTab(TAB_INDEX_FAVORITES);
- } else {
- mTabHost.setCurrentTab(TAB_INDEX_CONTACTS);
- }
- } else {
- // Not launched through the front door, look at the component to determine the tab
- String componentName = intent.getComponent().getClassName();
- if (getClass().getName().equals(componentName)) {
- if (recentCallsRequest) {
- mTabHost.setCurrentTab(TAB_INDEX_CALL_LOG);
- } else {
- mTabHost.setCurrentTab(TAB_INDEX_DIALER);
- }
- } else {
- mTabHost.setCurrentTab(mLastManuallySelectedTab);
- }
- }
-
- // Restore to the previous manual selection
- mLastManuallySelectedTab = savedTabIndex;
-
- // Tell the children activities that they should honor their saved states
- // instead of the state from the parent's intent
- intent.putExtra(EXTRA_IGNORE_STATE, false);
- }
-
- @Override
- public void onNewIntent(Intent newIntent) {
- setIntent(newIntent);
- fixIntent(newIntent);
- setCurrentTab(newIntent);
- final String action = newIntent.getAction();
- if (UI.FILTER_CONTACTS_ACTION.equals(action)) {
- setupFilterText(newIntent);
- } else if (isDialIntent(newIntent)) {
- setupDialUri(newIntent);
- }
- }
-
- /** Returns true if the given intent contains a phone number to populate the dialer with */
- private boolean isDialIntent(Intent intent) {
- final String action = intent.getAction();
- if (Intent.ACTION_DIAL.equals(action)) {
- return true;
- }
- if (Intent.ACTION_VIEW.equals(action)) {
- final Uri data = intent.getData();
- if (data != null && "tel".equals(data.getScheme())) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Retrieves the filter text stored in {@link #setupFilterText(Intent)}.
- * This text originally came from a FILTER_CONTACTS_ACTION intent received
- * by this activity. The stored text will then be cleared after after this
- * method returns.
- *
- * @return The stored filter text
- */
- public String getAndClearFilterText() {
- String filterText = mFilterText;
- mFilterText = null;
- return filterText;
- }
-
- /**
- * Stores the filter text associated with a FILTER_CONTACTS_ACTION intent.
- * This is so child activities can check if they are supposed to display a filter.
- *
- * @param intent The intent received in {@link #onNewIntent(Intent)}
- */
- private void setupFilterText(Intent intent) {
- // If the intent was relaunched from history, don't apply the filter text.
- if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
- return;
- }
- String filter = intent.getStringExtra(UI.FILTER_TEXT_EXTRA_KEY);
- if (filter != null && filter.length() > 0) {
- mFilterText = filter;
- }
- }
-
- /**
- * Retrieves the uri stored in {@link #setupDialUri(Intent)}. This uri
- * originally came from a dial intent received by this activity. The stored
- * uri will then be cleared after after this method returns.
- *
- * @return The stored uri
- */
- public Uri getAndClearDialUri() {
- Uri dialUri = mDialUri;
- mDialUri = null;
- return dialUri;
- }
-
- /**
- * Stores the uri associated with a dial intent. This is so child activities can
- * check if they are supposed to display new dial info.
- *
- * @param intent The intent received in {@link #onNewIntent(Intent)}
- */
- private void setupDialUri(Intent intent) {
- // If the intent was relaunched from history, don't reapply the intent.
- if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
- return;
- }
- mDialUri = intent.getData();
- }
-
- @Override
- public void onBackPressed() {
- if (isTaskRoot()) {
- // Instead of stopping, simply push this to the back of the stack.
- // This is only done when running at the top of the stack;
- // otherwise, we have been launched by someone else so need to
- // allow the user to go back to the caller.
- moveTaskToBack(false);
- } else {
- super.onBackPressed();
- }
- }
-
- /** {@inheritDoc} */
- public void onTabChanged(String tabId) {
- // Because we're using Activities as our tab children, we trigger
- // onWindowFocusChanged() to let them know when they're active. This may
- // seem to duplicate the purpose of onResume(), but it's needed because
- // onResume() can't reliably check if a keyguard is active.
- Activity activity = getLocalActivityManager().getActivity(tabId);
- if (activity != null) {
- activity.onWindowFocusChanged(true);
- }
-
- // Remember this tab index. This function is also called, if the tab is set automatically
- // in which case the setter (setCurrentTab) has to set this to its old value afterwards
- mLastManuallySelectedTab = mTabHost.getCurrentTab();
- }
-}
diff --git a/src/com/android/contacts/SpecialCharSequenceMgr.java b/src/com/android/contacts/SpecialCharSequenceMgr.java
index a047a68..9f9f40d 100644
--- a/src/com/android/contacts/SpecialCharSequenceMgr.java
+++ b/src/com/android/contacts/SpecialCharSequenceMgr.java
@@ -54,7 +54,7 @@
private SpecialCharSequenceMgr() {
}
- static boolean handleChars(Context context, String input, EditText textField) {
+ public static boolean handleChars(Context context, String input, EditText textField) {
return handleChars(context, input, false, textField);
}
diff --git a/src/com/android/contacts/TypePrecedence.java b/src/com/android/contacts/TypePrecedence.java
index 2adf3b5..e89c5aa 100644
--- a/src/com/android/contacts/TypePrecedence.java
+++ b/src/com/android/contacts/TypePrecedence.java
@@ -42,6 +42,7 @@
//TODO These may need to be tweaked.
private static final int[] TYPE_PRECEDENCE_PHONES = {
Phone.TYPE_CUSTOM,
+ Phone.TYPE_MAIN,
Phone.TYPE_MOBILE,
Phone.TYPE_HOME,
Phone.TYPE_WORK,
diff --git a/src/com/android/contacts/activities/ActionBarAdapter.java b/src/com/android/contacts/activities/ActionBarAdapter.java
index 9943e2d..7ca5921 100644
--- a/src/com/android/contacts/activities/ActionBarAdapter.java
+++ b/src/com/android/contacts/activities/ActionBarAdapter.java
@@ -29,7 +29,6 @@
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.View.OnFocusChangeListener;
import android.widget.SearchView;
import android.widget.SearchView.OnCloseListener;
import android.widget.SearchView.OnQueryTextListener;
@@ -38,8 +37,8 @@
/**
* Adapter for the action bar at the top of the Contacts activity.
*/
-public class ActionBarAdapter implements OnQueryTextListener, OnCloseListener,
- ContactListFilterListener, OnFocusChangeListener {
+public class ActionBarAdapter
+ implements OnQueryTextListener, OnCloseListener, ContactListFilterListener {
public interface Listener {
void onAction();
@@ -95,7 +94,6 @@
mSearchView.setOnQueryTextListener(this);
mSearchView.setOnCloseListener(this);
- mSearchView.setOnQueryTextFocusChangeListener(this);
mSearchView.setQuery(mQueryString, false);
mSearchView.setQueryHint(mContext.getString(R.string.hint_findContacts));
@@ -117,13 +115,6 @@
mFilterController.addListener(this);
}
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- if (v == mSearchView && hasFocus) {
- setSearchMode(true);
- }
- }
-
public boolean isSearchMode() {
return mSearchMode;
}
diff --git a/src/com/android/contacts/activities/CallLogActivity.java b/src/com/android/contacts/activities/CallLogActivity.java
new file mode 100644
index 0000000..13c3209
--- /dev/null
+++ b/src/com/android/contacts/activities/CallLogActivity.java
@@ -0,0 +1,133 @@
+/*
+ * 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.activities;
+
+import com.android.contacts.ContactsSearchManager;
+import com.android.contacts.R;
+import com.android.contacts.calllog.CallLogFragment;
+import com.android.internal.telephony.ITelephony;
+
+import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.ViewConfiguration;
+
+/**
+ * Displays a list of call log entries.
+ */
+public class CallLogActivity extends Activity {
+ private static final String TAG = "CallLogActivity";
+
+ private CallLogFragment mFragment;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+
+ setContentView(R.layout.call_log_activity);
+
+ // Typing here goes to the dialer
+ setDefaultKeyMode(DEFAULT_KEYS_DIALER);
+
+ mFragment = (CallLogFragment) getFragmentManager().findFragmentById(
+ R.id.call_log_fragment);
+ }
+
+ public CallLogFragment getFragment() {
+ return mFragment;
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ super.onWindowFocusChanged(hasFocus);
+
+ // Clear notifications only when window gains focus. This activity won't
+ // immediately receive focus if the keyguard screen is above it.
+ if (hasFocus) {
+ try {
+ ITelephony telephony =
+ ITelephony.Stub.asInterface(ServiceManager.getService("phone"));
+ if (telephony != null) {
+ telephony.cancelMissedCallsNotification();
+ } else {
+ Log.w(TAG, "Telephony service is null, can't call " +
+ "cancelMissedCallsNotification");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to clear missed calls notification due to remote exception");
+ }
+ }
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_CALL: {
+ long callPressDiff = SystemClock.uptimeMillis() - event.getDownTime();
+ if (callPressDiff >= ViewConfiguration.getLongPressTimeout()) {
+ // Launch voice dialer
+ Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ }
+ return true;
+ }
+ }
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_CALL:
+ try {
+ ITelephony phone = ITelephony.Stub.asInterface(
+ ServiceManager.checkService("phone"));
+ if (phone != null && !phone.isIdle()) {
+ // Let the super class handle it
+ break;
+ }
+ } catch (RemoteException re) {
+ // Fall through and try to call the contact
+ }
+
+ mFragment.callSelectedEntry();
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
+ @Override
+ public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
+ boolean globalSearch) {
+ if (globalSearch) {
+ super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
+ } else {
+ ContactsSearchManager.startSearch(this, initialQuery);
+ }
+ }
+}
diff --git a/src/com/android/contacts/activities/ContactBrowserActivity.java b/src/com/android/contacts/activities/ContactBrowserActivity.java
index 4c2411c..f6b3f2f 100644
--- a/src/com/android/contacts/activities/ContactBrowserActivity.java
+++ b/src/com/android/contacts/activities/ContactBrowserActivity.java
@@ -23,7 +23,7 @@
import com.android.contacts.interactions.ContactDeletionInteraction;
import com.android.contacts.interactions.GroupDeletionDialogFragment;
import com.android.contacts.interactions.GroupRenamingDialogFragment;
-import com.android.contacts.interactions.ImportExportInteraction;
+import com.android.contacts.interactions.ImportExportDialogFragment;
import com.android.contacts.interactions.PhoneNumberInteraction;
import com.android.contacts.list.ContactBrowseListContextMenuAdapter;
import com.android.contacts.list.ContactBrowseListFragment;
@@ -42,7 +42,6 @@
import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.preference.ContactsPreferenceActivity;
import com.android.contacts.util.AccountSelectionUtil;
-import com.android.contacts.util.AccountsListAdapter;
import com.android.contacts.util.DialogManager;
import com.android.contacts.widget.ContextMenuAdapter;
@@ -69,9 +68,6 @@
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ListPopupWindow;
import android.widget.Toast;
import java.util.ArrayList;
@@ -88,9 +84,8 @@
private static final String TAG = "ContactBrowserActivity";
private static final int SUBACTIVITY_NEW_CONTACT = 2;
- private static final int SUBACTIVITY_SETTINGS = 3;
- private static final int SUBACTIVITY_EDIT_CONTACT = 4;
- private static final int SUBACTIVITY_CUSTOMIZE_FILTER = 5;
+ private static final int SUBACTIVITY_EDIT_CONTACT = 3;
+ private static final int SUBACTIVITY_CUSTOMIZE_FILTER = 4;
private static final String KEY_SEARCH_MODE = "searchMode";
@@ -105,13 +100,18 @@
private boolean mSearchMode;
private ContactBrowseListFragment mListFragment;
+
+ /**
+ * Whether we have a right-side contact pane for displaying contact info while browsing.
+ * Generally means "this is a tablet".
+ */
private boolean mContactContentDisplayed;
+
private ContactDetailFragment mDetailFragment;
private DetailFragmentListener mDetailFragmentListener = new DetailFragmentListener();
private PhoneNumberInteraction mPhoneNumberCallInteraction;
private PhoneNumberInteraction mSendTextMessageInteraction;
- private ImportExportInteraction mImportExportInteraction;
private boolean mSearchInitiated;
@@ -125,7 +125,6 @@
private boolean mOptionsMenuContactsAvailable;
private boolean mOptionsMenuGroupActionsEnabled;
- private boolean mOptionsMenuCustomFilterChangeable;
public ContactBrowserActivity() {
mIntentResolver = new ContactsIntentResolver(this);
@@ -169,7 +168,8 @@
item.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- createNewContact();
+ final Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
+ startActivityForResult(intent, SUBACTIVITY_NEW_CONTACT);
}
});
@@ -215,13 +215,15 @@
setTitle(mRequest.getActivityTitle());
- mHasActionBar = getWindow().hasFeature(Window.FEATURE_ACTION_BAR);
- if (mHasActionBar) {
- ActionBar actionBar = getActionBar();
+ if (createContentView) {
+ mHasActionBar = getWindow().hasFeature(Window.FEATURE_ACTION_BAR);
+ if (mHasActionBar) {
+ ActionBar actionBar = getActionBar();
- mActionBarAdapter = new ActionBarAdapter(this);
- mActionBarAdapter.onCreate(savedState, mRequest, actionBar);
- mActionBarAdapter.setContactListFilterController(mContactListFilterController);
+ mActionBarAdapter = new ActionBarAdapter(this);
+ mActionBarAdapter.onCreate(savedState, mRequest, actionBar);
+ mActionBarAdapter.setContactListFilterController(mContactListFilterController);
+ }
}
configureFragments(savedState == null);
@@ -234,7 +236,6 @@
}
mOptionsMenuContactsAvailable = false;
- mOptionsMenuCustomFilterChangeable = false;
mOptionsMenuGroupActionsEnabled = false;
mProviderStatus = -1;
@@ -498,7 +499,7 @@
@Override
public void onDeleteContactAction(Uri contactUri) {
- ContactDeletionInteraction.start(ContactBrowserActivity.this, contactUri);
+ ContactDeletionInteraction.start(ContactBrowserActivity.this, contactUri, false);
}
@Override
@@ -545,7 +546,7 @@
@Override
public void onDeleteRequested(Uri contactUri) {
- ContactDeletionInteraction.start(ContactBrowserActivity.this, contactUri);
+ ContactDeletionInteraction.start(ContactBrowserActivity.this, contactUri, false);
}
@Override
@@ -635,7 +636,7 @@
final MenuItem addContact = menu.findItem(R.id.menu_add);
addContact.setActionView(mAddContactImageView);
return true;
- } else if (mRequest.getActionCode() == ContactsRequest.ACTION_DEFAULT ||
+ } else if (mRequest.getActionCode() == ContactsRequest.ACTION_ALL_CONTACTS ||
mRequest.getActionCode() == ContactsRequest.ACTION_STREQUENT) {
inflater.inflate(R.menu.list, menu);
return true;
@@ -663,10 +664,6 @@
return true;
}
- if (mOptionsMenuCustomFilterChangeable != isCustomFilterChangeable()) {
- return true;
- }
-
if (mListFragment != null && mListFragment.isOptionsMenuChanged()) {
return true;
}
@@ -686,13 +683,8 @@
}
MenuItem settings = menu.findItem(R.id.menu_settings);
- settings.setVisible(!ContactsPreferenceActivity.isEmpty(this));
-
- mOptionsMenuCustomFilterChangeable = isCustomFilterChangeable();
-
- MenuItem displayGroups = menu.findItem(R.id.menu_display_groups);
- if (displayGroups != null) {
- displayGroups.setVisible(mOptionsMenuCustomFilterChangeable);
+ if (settings != null) {
+ settings.setVisible(!ContactsPreferenceActivity.isEmpty(this));
}
mOptionsMenuGroupActionsEnabled = areGroupActionsEnabled();
@@ -723,16 +715,12 @@
return groupActionsEnabled;
}
- public boolean isCustomFilterChangeable() {
- return mRequest != null && mRequest.getActionCode() == ContactsRequest.ACTION_DEFAULT;
- }
-
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_settings: {
final Intent intent = new Intent(this, ContactsPreferenceActivity.class);
- startActivityForResult(intent, SUBACTIVITY_SETTINGS);
+ startActivity(intent);
return true;
}
case R.id.menu_search: {
@@ -745,7 +733,7 @@
return true;
}
case R.id.menu_import_export: {
- getImportExportInteraction().startInteraction();
+ ImportExportDialogFragment.show(getFragmentManager());
return true;
}
case R.id.menu_accounts: {
@@ -773,35 +761,6 @@
return false;
}
- private void createNewContact() {
- final ArrayList<Account> accounts =
- AccountTypeManager.getInstance(this).getAccounts(true);
- if (accounts.size() <= 1 || mAddContactImageView == null) {
- // No account to choose or no control to anchor the popup-menu to
- // ==> just go straight to the editor which will disambig if necessary
- final Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
- startActivityForResult(intent, SUBACTIVITY_NEW_CONTACT);
- return;
- }
-
- final ListPopupWindow popup = new ListPopupWindow(this, null);
- popup.setWidth(getResources().getDimensionPixelSize(R.dimen.account_selector_popup_width));
- popup.setAnchorView(mAddContactImageView);
- final AccountsListAdapter adapter = new AccountsListAdapter(this, true);
- popup.setAdapter(adapter);
- popup.setOnItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- popup.dismiss();
- final Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
- intent.putExtra(Intents.Insert.ACCOUNT, adapter.getItem(position));
- startActivityForResult(intent, SUBACTIVITY_NEW_CONTACT);
- }
- });
- popup.setModal(true);
- popup.show();
- }
-
@Override
public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
boolean globalSearch) {
@@ -822,9 +781,6 @@
dialog = getSendTextMessageInteraction().onCreateDialog(id, bundle);
if (dialog != null) return dialog;
- dialog = getImportExportInteraction().onCreateDialog(id, bundle);
- if (dialog != null) return dialog;
-
return super.onCreateDialog(id, bundle);
}
@@ -853,16 +809,13 @@
case SUBACTIVITY_EDIT_CONTACT:
case SUBACTIVITY_NEW_CONTACT: {
- if (resultCode == RESULT_OK) {
+ if (resultCode == RESULT_OK && mContactContentDisplayed) {
mRequest.setActionCode(ContactsRequest.ACTION_VIEW_CONTACT);
mListFragment.reloadDataAndSetSelectedUri(data.getData());
}
break;
}
- case SUBACTIVITY_SETTINGS:
- break;
-
// TODO: Using the new startActivityWithResultFromFragment API this should not be needed
// anymore
case ContactEntryListFragment.ACTIVITY_REQUEST_CODE_PICKER:
@@ -910,8 +863,7 @@
default: {
// Bring up the search UI if the user starts typing
final int unicodeChar = event.getUnicodeChar();
-
- if (unicodeChar != 0) {
+ if (unicodeChar != 0 && !Character.isWhitespace(unicodeChar)) {
String query = new String(new int[]{ unicodeChar }, 0, 1);
if (mHasActionBar) {
if (!mActionBarAdapter.isSearchMode()) {
@@ -989,13 +941,6 @@
return mSendTextMessageInteraction;
}
- private ImportExportInteraction getImportExportInteraction() {
- if (mImportExportInteraction == null) {
- mImportExportInteraction = new ImportExportInteraction(this);
- }
- return mImportExportInteraction;
- }
-
@Override
public DialogManager getDialogManager() {
return mDialogManager;
diff --git a/src/com/android/contacts/activities/ContactDetailActivity.java b/src/com/android/contacts/activities/ContactDetailActivity.java
index ca26280..0036256 100644
--- a/src/com/android/contacts/activities/ContactDetailActivity.java
+++ b/src/com/android/contacts/activities/ContactDetailActivity.java
@@ -22,6 +22,7 @@
import com.android.contacts.R;
import com.android.contacts.detail.ContactDetailFragment;
import com.android.contacts.interactions.ContactDeletionInteraction;
+import com.android.contacts.util.PhoneCapabilityTester;
import android.accounts.Account;
import android.content.ActivityNotFoundException;
@@ -44,6 +45,23 @@
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
+ if (PhoneCapabilityTester.isUsingTwoPanes(this)) {
+ // This activity must not be shown. We have to select the contact in the
+ // ContactBrowserActivity instead ==> Create a forward intent and finish
+ final Intent originalIntent = getIntent();
+ Intent intent = new Intent();
+ intent.setAction(originalIntent.getAction());
+ intent.setDataAndType(originalIntent.getData(), originalIntent.getType());
+ intent.setFlags(
+ Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_FORWARD_RESULT
+ | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+
+ intent.setClass(this, ContactBrowserActivity.class);
+ startActivity(intent);
+ finish();
+ return;
+ }
+
setContentView(R.layout.contact_detail_activity);
mFragment = (ContactDetailFragment) getFragmentManager().findFragmentById(
@@ -94,7 +112,7 @@
@Override
public void onDeleteRequested(Uri contactUri) {
- ContactDeletionInteraction.start(ContactDetailActivity.this, contactUri);
+ ContactDeletionInteraction.start(ContactDetailActivity.this, contactUri, true);
}
@Override
diff --git a/src/com/android/contacts/activities/ContactEditorActivity.java b/src/com/android/contacts/activities/ContactEditorActivity.java
index 00e0ab0..29ebd59 100644
--- a/src/com/android/contacts/activities/ContactEditorActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorActivity.java
@@ -50,10 +50,9 @@
private static final String TAG = "ContactEditorActivity";
public static final String ACTION_JOIN_COMPLETED = "joinCompleted";
+ public static final String ACTION_SAVE_COMPLETED = "saveCompleted";
private ContactEditorFragment mFragment;
- private Button mDoneButton;
- private Button mRevertButton;
private DialogManager mDialogManager = new DialogManager(this);
@@ -70,6 +69,11 @@
return;
}
+ if (ACTION_SAVE_COMPLETED.equals(action)) {
+ finish();
+ return;
+ }
+
setContentView(R.layout.contact_editor_activity);
// This Activity will always fall back to the "top" Contacts screen when touched on the
@@ -84,22 +88,6 @@
mFragment.setListener(mFragmentListener);
Uri uri = Intent.ACTION_EDIT.equals(action) ? getIntent().getData() : null;
mFragment.load(action, uri, getIntent().getExtras());
-
- // Depending on the use-case, this activity has Done and Revert buttons or not.
- mDoneButton = (Button) findViewById(R.id.done);
- mRevertButton = (Button) findViewById(R.id.revert);
- if (mDoneButton != null) mDoneButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mFragment.save(SaveMode.CLOSE);
- }
- });
- if (mRevertButton != null) mRevertButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- finish();
- }
- });
}
@Override
@@ -113,6 +101,10 @@
String action = intent.getAction();
if (Intent.ACTION_EDIT.equals(action)) {
mFragment.setIntentExtras(intent.getExtras());
+ } else if (ACTION_SAVE_COMPLETED.equals(action)) {
+ mFragment.onSaveCompleted(true,
+ intent.getIntExtra(ContactEditorFragment.SAVE_MODE_EXTRA_KEY, SaveMode.CLOSE),
+ intent.getData());
} else if (ACTION_JOIN_COMPLETED.equals(action)) {
mFragment.onJoinCompleted(intent.getData());
}
@@ -178,11 +170,6 @@
}
@Override
- public void onAccountSelectorAborted() {
- finish();
- }
-
- @Override
public void onContactNotFound() {
setResult(Activity.RESULT_CANCELED, null);
finish();
@@ -195,7 +182,7 @@
@Override
public void onDeleteRequested(Uri contactUri) {
- ContactDeletionInteraction.start(ContactEditorActivity.this, contactUri);
+ ContactDeletionInteraction.start(ContactEditorActivity.this, contactUri, true);
}
@Override
diff --git a/src/com/android/contacts/activities/ContactSelectionActivity.java b/src/com/android/contacts/activities/ContactSelectionActivity.java
index 4efc43f..c255ba1 100644
--- a/src/com/android/contacts/activities/ContactSelectionActivity.java
+++ b/src/com/android/contacts/activities/ContactSelectionActivity.java
@@ -23,7 +23,9 @@
import com.android.contacts.list.ContactsIntentResolver;
import com.android.contacts.list.ContactsRequest;
import com.android.contacts.list.DirectoryListLoader;
+import com.android.contacts.list.EmailAddressPickerFragment;
import com.android.contacts.list.OnContactPickerActionListener;
+import com.android.contacts.list.OnEmailAddressPickerActionListener;
import com.android.contacts.list.OnPhoneNumberPickerActionListener;
import com.android.contacts.list.OnPostalAddressPickerActionListener;
import com.android.contacts.list.PhoneNumberPickerFragment;
@@ -171,6 +173,11 @@
break;
}
+ case ContactsRequest.ACTION_PICK_EMAIL: {
+ setTitle(R.string.contactPickerActivityTitle);
+ break;
+ }
+
case ContactsRequest.ACTION_CREATE_SHORTCUT_CALL: {
setTitle(R.string.callShortcutActivityTitle);
break;
@@ -236,6 +243,11 @@
break;
}
+ case ContactsRequest.ACTION_PICK_EMAIL: {
+ mListFragment = new EmailAddressPickerFragment();
+ break;
+ }
+
case ContactsRequest.ACTION_CREATE_SHORTCUT_CALL: {
PhoneNumberPickerFragment fragment = new PhoneNumberPickerFragment();
fragment.setShortcutAction(Intent.ACTION_CALL);
@@ -284,6 +296,9 @@
} else if (mListFragment instanceof PostalAddressPickerFragment) {
((PostalAddressPickerFragment) mListFragment).setOnPostalAddressPickerActionListener(
new PostalAddressPickerActionListener());
+ } else if (mListFragment instanceof EmailAddressPickerFragment) {
+ ((EmailAddressPickerFragment) mListFragment).setOnEmailAddressPickerActionListener(
+ new EmailAddressPickerActionListener());
} else {
throw new IllegalStateException("Unsupported list fragment type: " + mListFragment);
}
@@ -334,6 +349,14 @@
}
}
+ private final class EmailAddressPickerActionListener implements
+ OnEmailAddressPickerActionListener {
+ @Override
+ public void onPickEmailAddressAction(Uri dataUri) {
+ returnPickerResult(dataUri);
+ }
+ }
+
public void startActivityAndForwardResult(final Intent intent) {
intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
diff --git a/src/com/android/contacts/activities/ContactsFrontDoor.java b/src/com/android/contacts/activities/ContactsFrontDoor.java
index 3677cce..d34f2c4 100644
--- a/src/com/android/contacts/activities/ContactsFrontDoor.java
+++ b/src/com/android/contacts/activities/ContactsFrontDoor.java
@@ -17,7 +17,6 @@
package com.android.contacts.activities;
import com.android.contacts.ContactsActivity;
-import com.android.contacts.DialtactsActivity;
import com.android.contacts.util.PhoneCapabilityTester;
import android.content.Intent;
@@ -39,12 +38,12 @@
| Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(EXTRA_FRONT_DOOR, true);
- if (PhoneCapabilityTester.isPhone(this)) {
- // Default to the normal dialtacts layout
- intent.setClass(this, DialtactsActivity.class);
- } else {
+ if (PhoneCapabilityTester.isUsingTwoPanes(this)) {
// No tabs, just a contact list
intent.setClass(this, ContactBrowserActivity.class);
+ } else {
+ // Default to the normal dialtacts layout
+ intent.setClass(this, DialtactsActivity.class);
}
startActivity(intent);
diff --git a/src/com/android/contacts/activities/DialpadActivity.java b/src/com/android/contacts/activities/DialpadActivity.java
new file mode 100644
index 0000000..bb122df
--- /dev/null
+++ b/src/com/android/contacts/activities/DialpadActivity.java
@@ -0,0 +1,159 @@
+/*
+ * 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.activities;
+
+import com.android.contacts.ContactsSearchManager;
+import com.android.contacts.R;
+import com.android.contacts.dialpad.DialpadFragment;
+
+import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.ViewConfiguration;
+import android.view.Window;
+import android.view.inputmethod.InputMethodManager;
+
+/**
+ * Activity that displays a twelve-key phone dialpad.
+ * This is just a simple container around DialpadFragment.
+ * @see DialpadFragment
+ */
+public class DialpadActivity extends Activity {
+ private static final String TAG = "DialpadActivity";
+
+ private DialpadFragment mFragment;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.dialpad_activity);
+
+ Resources r = getResources();
+ // Do not show title in the case the device is in carmode.
+ if ((r.getConfiguration().uiMode & Configuration.UI_MODE_TYPE_MASK) ==
+ Configuration.UI_MODE_TYPE_CAR) {
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ }
+
+ mFragment = (DialpadFragment) getFragmentManager().findFragmentById(
+ R.id.dialpad_fragment);
+
+ // Manually run the onRestoreInstanceState() sequence here, but only if
+ // our intent does *not* have the DialtactsActivity.EXTRA_IGNORE_STATE
+ // set (see the references to EXTRA_IGNORE_STATE in DialtactsActivity).
+ // TODO: Find a cleaner way of doing this.
+ if (!mFragment.resolveIntent() && (icicle != null)) {
+ super.onRestoreInstanceState(icicle);
+ }
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle icicle) {
+ // Do nothing, state is restored in onCreate() if needed
+ }
+
+ @Override
+ protected void onNewIntent(Intent newIntent) {
+ setIntent(newIntent);
+ mFragment.resolveIntent();
+ }
+
+ @Override
+ protected void onPostCreate(Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+
+ // Pass this lifecycle event down to the fragment
+ mFragment.onPostCreate();
+ }
+
+ public DialpadFragment getFragment() {
+ return mFragment;
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ if (hasFocus) {
+ // Hide soft keyboard, if visible (it's fugly over button dialer).
+ // The only known case where this will be true is when launching the dialer with
+ // ACTION_DIAL via a soft keyboard. we dismiss it here because we don't
+ // have a window token yet in onCreate / onNewIntent
+ InputMethodManager inputMethodManager = (InputMethodManager)
+ getSystemService(Context.INPUT_METHOD_SERVICE);
+ inputMethodManager.hideSoftInputFromWindow(
+ mFragment.getDigitsWidget().getWindowToken(), 0);
+ }
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_CALL: {
+ long callPressDiff = SystemClock.uptimeMillis() - event.getDownTime();
+ if (callPressDiff >= ViewConfiguration.getLongPressTimeout()) {
+ // Launch voice dialer
+ Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.w(TAG, "Failed to launch voice dialer: " + e);
+ }
+ }
+ return true;
+ }
+ case KeyEvent.KEYCODE_1: {
+ long timeDiff = SystemClock.uptimeMillis() - event.getDownTime();
+ if (timeDiff >= ViewConfiguration.getLongPressTimeout()) {
+ // Long press detected, call voice mail
+ mFragment.callVoicemail();
+ }
+ return true;
+ }
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_CALL: {
+ mFragment.dialButtonPressed();
+ return true;
+ }
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
+ @Override
+ public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
+ boolean globalSearch) {
+ if (globalSearch) {
+ super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
+ } else {
+ ContactsSearchManager.startSearch(this, initialQuery);
+ }
+ }
+}
diff --git a/src/com/android/contacts/activities/DialtactsActivity.java b/src/com/android/contacts/activities/DialtactsActivity.java
new file mode 100644
index 0000000..baae703
--- /dev/null
+++ b/src/com/android/contacts/activities/DialtactsActivity.java
@@ -0,0 +1,558 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.activities;
+
+import com.android.contacts.R;
+import com.android.contacts.calllog.CallLogFragment;
+import com.android.contacts.dialpad.DialpadFragment;
+import com.android.contacts.interactions.ImportExportDialogFragment;
+import com.android.contacts.list.ContactListFilter;
+import com.android.contacts.list.ContactsIntentResolver;
+import com.android.contacts.list.ContactsRequest;
+import com.android.contacts.list.DefaultContactBrowseListFragment;
+import com.android.contacts.list.DirectoryListLoader;
+import com.android.contacts.list.OnContactBrowserActionListener;
+import com.android.contacts.preference.ContactsPreferenceActivity;
+import com.android.internal.telephony.ITelephony;
+
+import android.app.ActionBar;
+import android.app.ActionBar.Tab;
+import android.app.ActionBar.TabListener;
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.CallLog.Calls;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Intents.UI;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+
+/**
+ * The dialer activity that has one tab with the virtual 12key
+ * dialer, a tab with recent calls in it, a tab with the contacts and
+ * a tab with the favorite. This is the container and the tabs are
+ * embedded using intents.
+ * The dialer tab's title is 'phone', a more common name (see strings.xml).
+ */
+public class DialtactsActivity extends Activity {
+ private static final String TAG = "DialtactsActivity";
+
+ private static final int TAB_INDEX_DIALER = 0;
+ private static final int TAB_INDEX_CALL_LOG = 1;
+ private static final int TAB_INDEX_CONTACTS = 2;
+ private static final int TAB_INDEX_FAVORITES = 3;
+
+ public static final String EXTRA_IGNORE_STATE = "ignore-state";
+
+ /** Name of the dialtacts shared preferences */
+ static final String PREFS_DIALTACTS = "dialtacts";
+ /** If true, when handling the contacts intent the favorites tab will be shown instead */
+ static final String PREF_FAVORITES_AS_CONTACTS = "favorites_as_contacts";
+ static final boolean PREF_FAVORITES_AS_CONTACTS_DEFAULT = false;
+
+ /** Last manually selected tab index */
+ private static final String PREF_LAST_MANUALLY_SELECTED_TAB = "last_manually_selected_tab";
+ private static final int PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT = TAB_INDEX_DIALER;
+
+ private String mFilterText;
+ private Uri mDialUri;
+ private DialpadFragment mDialpadFragment;
+ private CallLogFragment mCallLogFragment;
+ private DefaultContactBrowseListFragment mContactsFragment;
+ private DefaultContactBrowseListFragment mFavoritesFragment;
+
+ /**
+ * The index of the tab that has last been manually selected (the user clicked on a tab).
+ * This value does not keep track of programmatically set Tabs (e.g. Call Log after a Call)
+ */
+ private int mLastManuallySelectedTab;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ final Intent intent = getIntent();
+ fixIntent(intent);
+
+ setContentView(R.layout.dialtacts_activity);
+
+ final FragmentManager fragmentManager = getFragmentManager();
+ mDialpadFragment = (DialpadFragment) fragmentManager
+ .findFragmentById(R.id.dialpad_fragment);
+ mCallLogFragment = (CallLogFragment) fragmentManager
+ .findFragmentById(R.id.call_log_fragment);
+ mContactsFragment = (DefaultContactBrowseListFragment) fragmentManager
+ .findFragmentById(R.id.contacts_fragment);
+ mFavoritesFragment = (DefaultContactBrowseListFragment) fragmentManager
+ .findFragmentById(R.id.favorites_fragment);
+
+ // Hide all tabs (the current tab will later be reshown once a tab is selected)
+ final FragmentTransaction transaction = fragmentManager.beginTransaction();
+ transaction.hide(mDialpadFragment);
+ transaction.hide(mCallLogFragment);
+ transaction.hide(mContactsFragment);
+ transaction.hide(mFavoritesFragment);
+ transaction.commit();
+
+ // Setup the ActionBar tabs (the order matches the tab-index contants TAB_INDEX_*)
+ setupDialer();
+ setupCallLog();
+ setupContacts();
+ setupFavorites();
+ getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+ getActionBar().setDisplayShowTitleEnabled(false);
+ getActionBar().setDisplayShowHomeEnabled(false);
+
+ // Load the last manually loaded tab
+ final SharedPreferences prefs = getSharedPreferences(PREFS_DIALTACTS, MODE_PRIVATE);
+ mLastManuallySelectedTab = prefs.getInt(PREF_LAST_MANUALLY_SELECTED_TAB,
+ PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT);
+
+ setCurrentTab(intent);
+
+ if (UI.FILTER_CONTACTS_ACTION.equals(intent.getAction())
+ && icicle == null) {
+ setupFilterText(intent);
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ final int currentTabIndex = getActionBar().getSelectedTab().getPosition();
+ final SharedPreferences.Editor editor =
+ getSharedPreferences(PREFS_DIALTACTS, MODE_PRIVATE).edit();
+ if (currentTabIndex == TAB_INDEX_CONTACTS || currentTabIndex == TAB_INDEX_FAVORITES) {
+ editor.putBoolean(PREF_FAVORITES_AS_CONTACTS, currentTabIndex == TAB_INDEX_FAVORITES);
+ }
+ editor.putInt(PREF_LAST_MANUALLY_SELECTED_TAB, mLastManuallySelectedTab);
+
+ editor.apply();
+ }
+
+ private void fixIntent(Intent intent) {
+ // This should be cleaned up: the call key used to send an Intent
+ // that just said to go to the recent calls list. It now sends this
+ // abstract action, but this class hasn't been rewritten to deal with it.
+ if (Intent.ACTION_CALL_BUTTON.equals(intent.getAction())) {
+ intent.setDataAndType(Calls.CONTENT_URI, Calls.CONTENT_TYPE);
+ intent.putExtra("call_key", true);
+ setIntent(intent);
+ }
+ }
+
+ private void setupDialer() {
+ final Tab tab = getActionBar().newTab();
+ tab.setText(R.string.dialerIconLabel);
+ tab.setTabListener(new TabChangeListener(mDialpadFragment));
+ tab.setIcon(R.drawable.ic_tab_dialer);
+ getActionBar().addTab(tab);
+ mDialpadFragment.resolveIntent();
+ }
+
+ private void setupCallLog() {
+ final Tab tab = getActionBar().newTab();
+ tab.setText(R.string.recentCallsIconLabel);
+ tab.setIcon(R.drawable.ic_tab_recent);
+ tab.setTabListener(new TabChangeListener(mCallLogFragment));
+ getActionBar().addTab(tab);
+ }
+
+ private void setupContacts() {
+ final Tab tab = getActionBar().newTab();
+ tab.setText(R.string.contactsIconLabel);
+ tab.setIcon(R.drawable.ic_tab_contacts);
+ tab.setTabListener(new TabChangeListener(mContactsFragment));
+ getActionBar().addTab(tab);
+
+ // TODO: We should not artificially create Intents and put them into the Fragment.
+ // It would be nicer to directly pass in the UI constant
+ Intent intent = new Intent(UI.LIST_ALL_CONTACTS_ACTION);
+ intent.setClass(this, ContactBrowserActivity.class);
+
+ ContactsIntentResolver resolver = new ContactsIntentResolver(this);
+ ContactsRequest request = resolver.resolveIntent(intent);
+ final ContactListFilter filter = new ContactListFilter(
+ ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS);
+ mContactsFragment.setFilter(filter, false);
+ mContactsFragment.setSearchMode(request.isSearchMode());
+ mContactsFragment.setQueryString(request.getQueryString(), false);
+ mContactsFragment.setContactsRequest(request);
+ mContactsFragment.setDirectorySearchMode(request.isDirectorySearchEnabled()
+ ? DirectoryListLoader.SEARCH_MODE_DEFAULT
+ : DirectoryListLoader.SEARCH_MODE_NONE);
+ mContactsFragment.setOnContactListActionListener(mListFragmentListener);
+ }
+
+ private void setupFavorites() {
+ final Tab tab = getActionBar().newTab();
+ tab.setText(R.string.contactsFavoritesLabel);
+ tab.setIcon(R.drawable.ic_tab_starred);
+ tab.setTabListener(new TabChangeListener(mFavoritesFragment));
+ getActionBar().addTab(tab);
+
+ // TODO: We should not artificially create Intents and put them into the Fragment.
+ // It would be nicer to directly pass in the UI constant
+ Intent intent = new Intent(UI.LIST_STREQUENT_ACTION);
+ intent.setClass(this, ContactBrowserActivity.class);
+
+ ContactsIntentResolver resolver = new ContactsIntentResolver(this);
+ ContactsRequest request = resolver.resolveIntent(intent);
+ final ContactListFilter filter = new ContactListFilter(
+ ContactListFilter.FILTER_TYPE_STARRED);
+ mFavoritesFragment.setFilter(filter, false);
+ mFavoritesFragment.setSearchMode(request.isSearchMode());
+ mFavoritesFragment.setQueryString(request.getQueryString(), false);
+ mFavoritesFragment.setContactsRequest(request);
+ mFavoritesFragment.setDirectorySearchMode(request.isDirectorySearchEnabled()
+ ? DirectoryListLoader.SEARCH_MODE_DEFAULT
+ : DirectoryListLoader.SEARCH_MODE_NONE);
+ mFavoritesFragment.setOnContactListActionListener(mListFragmentListener);
+ }
+
+ /**
+ * Returns true if the intent is due to hitting the green send key while in a call.
+ *
+ * @param intent the intent that launched this activity
+ * @param recentCallsRequest true if the intent is requesting to view recent calls
+ * @return true if the intent is due to hitting the green send key while in a call
+ */
+ private boolean isSendKeyWhileInCall(final Intent intent, final boolean recentCallsRequest) {
+ // If there is a call in progress go to the call screen
+ if (recentCallsRequest) {
+ final boolean callKey = intent.getBooleanExtra("call_key", false);
+
+ try {
+ ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
+ if (callKey && phone != null && phone.showCallScreen()) {
+ return true;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to handle send while in call", e);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Sets the current tab based on the intent's request type
+ *
+ * @param intent Intent that contains information about which tab should be selected
+ */
+ private void setCurrentTab(Intent intent) {
+ // If we got here by hitting send and we're in call forward along to the in-call activity
+ final boolean recentCallsRequest = Calls.CONTENT_TYPE.equals(intent.getType());
+ if (isSendKeyWhileInCall(intent, recentCallsRequest)) {
+ finish();
+ return;
+ }
+
+ // Tell the children activities that they should ignore any possible saved
+ // state and instead reload their state from the parent's intent
+ intent.putExtra(EXTRA_IGNORE_STATE, true);
+
+ // Remember the old manually selected tab index so that it can be restored if it is
+ // overwritten by one of the programmatic tab selections
+ final int savedTabIndex = mLastManuallySelectedTab;
+
+ // Choose the tab based on the inbound intent
+ if (intent.getBooleanExtra(ContactsFrontDoor.EXTRA_FRONT_DOOR, false)) {
+ // Launched through the contacts front door, set the proper contacts tab (sticky
+ // between favorites and contacts)
+ SharedPreferences prefs = getSharedPreferences(PREFS_DIALTACTS, MODE_PRIVATE);
+ boolean favoritesAsContacts = prefs.getBoolean(PREF_FAVORITES_AS_CONTACTS,
+ PREF_FAVORITES_AS_CONTACTS_DEFAULT);
+ if (favoritesAsContacts) {
+ getActionBar().selectTab(getActionBar().getTabAt(TAB_INDEX_FAVORITES));
+ } else {
+ getActionBar().selectTab(getActionBar().getTabAt(TAB_INDEX_CONTACTS));
+ }
+ } else {
+ // Not launched through the front door, look at the component to determine the tab
+ String componentName = intent.getComponent().getClassName();
+ if (getClass().getName().equals(componentName)) {
+ if (recentCallsRequest) {
+ getActionBar().selectTab(getActionBar().getTabAt(TAB_INDEX_CALL_LOG));
+ } else {
+ getActionBar().selectTab(getActionBar().getTabAt(TAB_INDEX_DIALER));
+ }
+ } else {
+ getActionBar().selectTab(getActionBar().getTabAt(mLastManuallySelectedTab));
+ }
+ }
+
+ // Restore to the previous manual selection
+ mLastManuallySelectedTab = savedTabIndex;
+
+ // Tell the children activities that they should honor their saved states
+ // instead of the state from the parent's intent
+ intent.putExtra(EXTRA_IGNORE_STATE, false);
+ }
+
+ @Override
+ public void onNewIntent(Intent newIntent) {
+ setIntent(newIntent);
+ fixIntent(newIntent);
+ setCurrentTab(newIntent);
+ final String action = newIntent.getAction();
+ if (UI.FILTER_CONTACTS_ACTION.equals(action)) {
+ setupFilterText(newIntent);
+ } else if (isDialIntent(newIntent)) {
+ setupDialUri(newIntent);
+ }
+ }
+
+ /** Returns true if the given intent contains a phone number to populate the dialer with */
+ private boolean isDialIntent(Intent intent) {
+ final String action = intent.getAction();
+ if (Intent.ACTION_DIAL.equals(action)) {
+ return true;
+ }
+ if (Intent.ACTION_VIEW.equals(action)) {
+ final Uri data = intent.getData();
+ if (data != null && "tel".equals(data.getScheme())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Retrieves the filter text stored in {@link #setupFilterText(Intent)}.
+ * This text originally came from a FILTER_CONTACTS_ACTION intent received
+ * by this activity. The stored text will then be cleared after after this
+ * method returns.
+ *
+ * @return The stored filter text
+ */
+ public String getAndClearFilterText() {
+ String filterText = mFilterText;
+ mFilterText = null;
+ return filterText;
+ }
+
+ /**
+ * Stores the filter text associated with a FILTER_CONTACTS_ACTION intent.
+ * This is so child activities can check if they are supposed to display a filter.
+ *
+ * @param intent The intent received in {@link #onNewIntent(Intent)}
+ */
+ private void setupFilterText(Intent intent) {
+ // If the intent was relaunched from history, don't apply the filter text.
+ if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
+ return;
+ }
+ String filter = intent.getStringExtra(UI.FILTER_TEXT_EXTRA_KEY);
+ if (filter != null && filter.length() > 0) {
+ mFilterText = filter;
+ }
+ }
+
+ /**
+ * Retrieves the uri stored in {@link #setupDialUri(Intent)}. This uri
+ * originally came from a dial intent received by this activity. The stored
+ * uri will then be cleared after after this method returns.
+ *
+ * @return The stored uri
+ */
+ public Uri getAndClearDialUri() {
+ Uri dialUri = mDialUri;
+ mDialUri = null;
+ return dialUri;
+ }
+
+ /**
+ * Stores the uri associated with a dial intent. This is so child activities can
+ * check if they are supposed to display new dial info.
+ *
+ * @param intent The intent received in {@link #onNewIntent(Intent)}
+ */
+ private void setupDialUri(Intent intent) {
+ // If the intent was relaunched from history, don't reapply the intent.
+ if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
+ return;
+ }
+ mDialUri = intent.getData();
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (isTaskRoot()) {
+ // Instead of stopping, simply push this to the back of the stack.
+ // This is only done when running at the top of the stack;
+ // otherwise, we have been launched by someone else so need to
+ // allow the user to go back to the caller.
+ moveTaskToBack(false);
+ } else {
+ super.onBackPressed();
+ }
+ }
+
+ @Override
+ protected void onPostCreate(Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+
+ // Pass this lifecycle event down to the fragment
+ mDialpadFragment.onPostCreate();
+ }
+
+ /**
+ * Tab change listener that is instantiated once for each tab. Handles showing/hiding tabs
+ * and remembers manual tab selections
+ */
+ private class TabChangeListener implements TabListener {
+ private final Fragment mFragment;
+
+ public TabChangeListener(Fragment fragment) {
+ mFragment = fragment;
+ }
+
+ @Override
+ public void onTabUnselected(Tab tab, FragmentTransaction ft) {
+ ft.hide(mFragment);
+ }
+
+ @Override
+ public void onTabSelected(Tab tab, FragmentTransaction ft) {
+ ft.show(mFragment);
+
+ // Remember this tab index. This function is also called, if the tab is set
+ // automatically in which case the setter (setCurrentTab) has to set this to its old
+ // value afterwards
+ mLastManuallySelectedTab = tab.getPosition();
+ }
+
+ @Override
+ public void onTabReselected(Tab tab, FragmentTransaction ft) {
+ }
+ }
+
+ private OnContactBrowserActionListener mListFragmentListener =
+ new OnContactBrowserActionListener() {
+ @Override
+ public void onViewContactAction(Uri contactLookupUri) {
+ startActivity(new Intent(Intent.ACTION_VIEW, contactLookupUri));
+ }
+
+ @Override
+ public void onSmsContactAction(Uri contactUri) {
+ }
+
+ @Override
+ public void onSelectionChange() {
+ }
+
+ @Override
+ public void onRemoveFromFavoritesAction(Uri contactUri) {
+ }
+
+ @Override
+ public void onInvalidSelection() {
+ }
+
+ @Override
+ public void onFinishAction() {
+ }
+
+ @Override
+ public void onEditContactAction(Uri contactLookupUri) {
+ }
+
+ @Override
+ public void onDeleteContactAction(Uri contactUri) {
+ }
+
+ @Override
+ public void onCreateNewContactAction() {
+ }
+
+ @Override
+ public void onCallContactAction(Uri contactUri) {
+ }
+
+ @Override
+ public void onAddToFavoritesAction(Uri contactUri) {
+ }
+ };
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // For now, create the menu in here. It would be nice to do this in the Fragment,
+ // but that Fragment is re-used in other views.
+ final ActionBar actionBar = getActionBar();
+ if (actionBar == null) return false;
+ final Tab tab = actionBar.getSelectedTab();
+ if (tab == null) return false;
+ final int tabIndex = tab.getPosition();
+ if (tabIndex != TAB_INDEX_CONTACTS && tabIndex != TAB_INDEX_FAVORITES) return false;
+
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.list, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // This is currently a copy of the equivalent code of ContactBrowserActivity (with the
+ // exception of menu_add, because we do not select items in the list).
+ // Should be consolidated
+ switch (item.getItemId()) {
+ case R.id.menu_settings: {
+ final Intent intent = new Intent(this, ContactsPreferenceActivity.class);
+ startActivity(intent);
+ return true;
+ }
+ case R.id.menu_search: {
+ onSearchRequested();
+ return true;
+ }
+ case R.id.menu_add: {
+ final Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
+ startActivity(intent);
+ return true;
+ }
+ case R.id.menu_import_export: {
+ ImportExportDialogFragment.show(getFragmentManager());
+ return true;
+ }
+ case R.id.menu_accounts: {
+ final Intent intent = new Intent(Settings.ACTION_SYNC_SETTINGS);
+ intent.putExtra(Settings.EXTRA_AUTHORITIES, new String[] {
+ ContactsContract.AUTHORITY
+ });
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+ startActivity(intent);
+ return true;
+ }
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+}
diff --git a/src/com/android/contacts/activities/GroupBrowserActivity.java b/src/com/android/contacts/activities/GroupBrowserActivity.java
new file mode 100644
index 0000000..e8b3ad8
--- /dev/null
+++ b/src/com/android/contacts/activities/GroupBrowserActivity.java
@@ -0,0 +1,55 @@
+/*
+ * 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.activities;
+
+import com.android.contacts.ContactsActivity;
+import com.android.contacts.R;
+
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * Displays a list to browse groups.
+ */
+public class GroupBrowserActivity extends ContactsActivity {
+
+ private static final String TAG = "GroupBrowserActivity";
+
+ public GroupBrowserActivity() {
+ }
+
+ @Override
+ protected void onCreate(Bundle savedState) {
+ super.onCreate(savedState);
+ configureContentView(true, savedState);
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ setIntent(intent);
+ configureContentView(false, null);
+ }
+
+ private void configureContentView(boolean createContentView, Bundle savedState) {
+ // TODO: Create Intent Resolver to handle the different ways users can get to this list.
+ // TODO: Use savedState if necessary
+ // TODO: Setup action bar
+ if (createContentView) {
+ setContentView(R.layout.group_browser_activity);
+ }
+ }
+}
diff --git a/src/com/android/contacts/activities/GroupDetailActivity.java b/src/com/android/contacts/activities/GroupDetailActivity.java
new file mode 100644
index 0000000..edc460c
--- /dev/null
+++ b/src/com/android/contacts/activities/GroupDetailActivity.java
@@ -0,0 +1,44 @@
+/*
+ * 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.activities;
+
+import com.android.contacts.ContactsActivity;
+import com.android.contacts.R;
+
+import android.os.Bundle;
+
+public class GroupDetailActivity extends ContactsActivity {
+
+ private static final String TAG = "GroupDetailActivity";
+
+ public static final String KEY_ACCOUNT_TYPE = "accountType";
+ public static final String KEY_ACCOUNT_NAME = "accountName";
+ public static final String KEY_GROUP_ID = "groupId";
+ public static final String KEY_GROUP_SOURCE_ID = "groupSourceId";
+ public static final String KEY_GROUP_READ_ONLY = "groupReadOnly";
+ public static final String KEY_GROUP_TITLE = "title";
+
+ @Override
+ public void onCreate(Bundle savedState) {
+ super.onCreate(savedState);
+
+ // TODO: Create Intent Resolver to handle the different ways users can get to this list.
+ // TODO: Handle search or key down
+
+ setContentView(R.layout.group_detail_activity);
+ }
+}
diff --git a/src/com/android/contacts/RecentCallsListActivity.java b/src/com/android/contacts/calllog/CallLogFragment.java
similarity index 76%
rename from src/com/android/contacts/RecentCallsListActivity.java
rename to src/com/android/contacts/calllog/CallLogFragment.java
index 0a3c178..5872043 100644
--- a/src/com/android/contacts/RecentCallsListActivity.java
+++ b/src/com/android/contacts/calllog/CallLogFragment.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * 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.
@@ -14,23 +14,20 @@
* limitations under the License.
*/
-package com.android.contacts;
+package com.android.contacts.calllog;
import com.android.common.widget.GroupingListAdapter;
+import com.android.contacts.CallDetailActivity;
+import com.android.contacts.ContactsUtils;
+import com.android.contacts.R;
import com.android.internal.telephony.CallerInfo;
-import com.android.internal.telephony.ITelephony;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.ListActivity;
-import android.content.ActivityNotFoundException;
+import android.app.ListFragment;
import android.content.AsyncQueryHandler;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
-import android.content.DialogInterface.OnClickListener;
import android.database.CharArrayBuffer;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabaseCorruptException;
@@ -43,9 +40,6 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
import android.provider.CallLog;
import android.provider.CallLog.Calls;
import android.provider.ContactsContract.CommonDataKinds.Phone;
@@ -60,15 +54,14 @@
import android.text.format.DateUtils;
import android.util.Log;
import android.view.ContextMenu;
-import android.view.KeyEvent;
+import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.Menu;
+import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
-import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
@@ -81,65 +74,70 @@
/**
* Displays a list of call log entries.
*/
-public class RecentCallsListActivity extends ListActivity
+public class CallLogFragment extends ListFragment
implements View.OnCreateContextMenuListener {
- private static final String TAG = "RecentCallsList";
+ private static final String TAG = "CallLogFragment";
- /** The projection to use when querying the call log table */
- static final String[] CALL_LOG_PROJECTION = new String[] {
- Calls._ID,
- Calls.NUMBER,
- Calls.DATE,
- Calls.DURATION,
- Calls.TYPE,
- Calls.CACHED_NAME,
- Calls.CACHED_NUMBER_TYPE,
- Calls.CACHED_NUMBER_LABEL,
- Calls.COUNTRY_ISO};
+ /** The query for the call log table */
+ private static final class CallLogQuery {
+ public static final String[] _PROJECTION = new String[] {
+ Calls._ID,
+ Calls.NUMBER,
+ Calls.DATE,
+ Calls.DURATION,
+ Calls.TYPE,
+ Calls.CACHED_NAME,
+ Calls.CACHED_NUMBER_TYPE,
+ Calls.CACHED_NUMBER_LABEL,
+ Calls.COUNTRY_ISO};
- static final int ID_COLUMN_INDEX = 0;
- static final int NUMBER_COLUMN_INDEX = 1;
- static final int DATE_COLUMN_INDEX = 2;
- static final int DURATION_COLUMN_INDEX = 3;
- static final int CALL_TYPE_COLUMN_INDEX = 4;
- static final int CALLER_NAME_COLUMN_INDEX = 5;
- static final int CALLER_NUMBERTYPE_COLUMN_INDEX = 6;
- static final int CALLER_NUMBERLABEL_COLUMN_INDEX = 7;
- static final int COUNTRY_ISO_COLUMN_INDEX = 8;
+ public static final int ID = 0;
+ public static final int NUMBER = 1;
+ public static final int DATE = 2;
+ public static final int DURATION = 3;
+ public static final int CALL_TYPE = 4;
+ public static final int CALLER_NAME = 5;
+ public static final int CALLER_NUMBERTYPE = 6;
+ public static final int CALLER_NUMBERLABEL = 7;
+ public static final int COUNTRY_ISO = 8;
+ }
- /** The projection to use when querying the phones table */
- static final String[] PHONES_PROJECTION = new String[] {
- PhoneLookup._ID,
- PhoneLookup.DISPLAY_NAME,
- PhoneLookup.TYPE,
- PhoneLookup.LABEL,
- PhoneLookup.NUMBER,
- PhoneLookup.NORMALIZED_NUMBER};
+ /** The query to use for the phones table */
+ private static final class PhoneQuery {
+ public static final String[] _PROJECTION = new String[] {
+ PhoneLookup._ID,
+ PhoneLookup.DISPLAY_NAME,
+ PhoneLookup.TYPE,
+ PhoneLookup.LABEL,
+ PhoneLookup.NUMBER,
+ PhoneLookup.NORMALIZED_NUMBER};
- static final int PERSON_ID_COLUMN_INDEX = 0;
- static final int NAME_COLUMN_INDEX = 1;
- static final int PHONE_TYPE_COLUMN_INDEX = 2;
- static final int LABEL_COLUMN_INDEX = 3;
- static final int MATCHED_NUMBER_COLUMN_INDEX = 4;
- static final int NORMALIZED_NUMBER_COLUMN_INDEX = 5;
+ public static final int PERSON_ID = 0;
+ public static final int NAME = 1;
+ public static final int PHONE_TYPE = 2;
+ public static final int LABEL = 3;
+ public static final int MATCHED_NUMBER = 4;
+ public static final int NORMALIZED_NUMBER = 5;
+ }
- private static final int MENU_ITEM_DELETE = 1;
- private static final int MENU_ITEM_DELETE_ALL = 2;
- private static final int MENU_ITEM_VIEW_CONTACTS = 3;
+ private static final class MenuItems {
+ public static final int DELETE = 1;
+ }
+
+ private static final class OptionsMenuItems {
+ public static final int DELETE_ALL = 1;
+ }
private static final int QUERY_TOKEN = 53;
private static final int UPDATE_TOKEN = 54;
- private static final int DIALOG_CONFIRM_DELETE_ALL = 1;
-
- RecentCallsAdapter mAdapter;
+ private CallLogAdapter mAdapter;
private QueryHandler mQueryHandler;
- String mVoiceMailNumber;
+ private String mVoiceMailNumber;
private String mCurrentCountryIso;
-
private boolean mScrollToTop;
- static final class ContactInfo {
+ public static final class ContactInfo {
public long personId;
public String name;
public int type;
@@ -151,27 +149,27 @@
public static ContactInfo EMPTY = new ContactInfo();
}
- public static final class RecentCallsListItemViews {
- TextView line1View;
- TextView labelView;
- TextView numberView;
- TextView dateView;
- ImageView iconView;
- View callView;
- ImageView groupIndicator;
- TextView groupSize;
+ public static final class CallLogListItemViews {
+ public TextView line1View;
+ public TextView labelView;
+ public TextView numberView;
+ public TextView dateView;
+ public ImageView iconView;
+ public View callView;
+ public ImageView groupIndicator;
+ public TextView groupSize;
}
- static final class CallerInfoQuery {
- String number;
- int position;
- String name;
- int numberType;
- String numberLabel;
+ public static final class CallerInfoQuery {
+ public String number;
+ public int position;
+ public String name;
+ public int numberType;
+ public String numberLabel;
}
/** Adapter class to fill in data for the Call Log */
- final class RecentCallsAdapter extends GroupingListAdapter
+ public final class CallLogAdapter extends GroupingListAdapter
implements Runnable, ViewTreeObserver.OnPreDrawListener, View.OnClickListener {
HashMap<String,ContactInfo> mContactInfo;
private final LinkedList<CallerInfoQuery> mRequests;
@@ -195,6 +193,7 @@
private CharArrayBuffer mBuffer1 = new CharArrayBuffer(128);
private CharArrayBuffer mBuffer2 = new CharArrayBuffer(128);
+ @Override
public void onClick(View view) {
String number = (String) view.getTag();
if (!TextUtils.isEmpty(number)) {
@@ -211,6 +210,7 @@
}
}
+ @Override
public boolean onPreDraw() {
if (mFirst) {
mHandler.sendEmptyMessageDelayed(START_THREAD, 1000);
@@ -233,8 +233,8 @@
}
};
- public RecentCallsAdapter() {
- super(RecentCallsListActivity.this);
+ public CallLogAdapter() {
+ super(getActivity());
mContactInfo = new HashMap<String,ContactInfo>();
mRequests = new LinkedList<CallerInfoQuery>();
@@ -307,7 +307,7 @@
values.put(Calls.CACHED_NUMBER_LABEL, ci.label);
try {
- RecentCallsListActivity.this.getContentResolver().update(Calls.CONTENT_URI, values,
+ getActivity().getContentResolver().update(Calls.CONTENT_URI, values,
Calls.NUMBER + "='" + ciq.number + "'", null);
} catch (SQLiteDiskIOException e) {
Log.w(TAG, "Exception while updating call info", e);
@@ -369,7 +369,7 @@
String[] selectionArgs = new String[] { ciq.number.toUpperCase() };
Cursor dataTableCursor =
- RecentCallsListActivity.this.getContentResolver().query(
+ getActivity().getContentResolver().query(
contactRef,
null, // projection
selection, // selection
@@ -410,20 +410,21 @@
// "number" is a regular phone number, so use the
// PhoneLookup table:
Cursor phonesCursor =
- RecentCallsListActivity.this.getContentResolver().query(
+ getActivity().getContentResolver().query(
Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(ciq.number)),
- PHONES_PROJECTION, null, null, null);
+ PhoneQuery._PROJECTION, null, null, null);
if (phonesCursor != null) {
if (phonesCursor.moveToFirst()) {
info = new ContactInfo();
- info.personId = phonesCursor.getLong(PERSON_ID_COLUMN_INDEX);
- info.name = phonesCursor.getString(NAME_COLUMN_INDEX);
- info.type = phonesCursor.getInt(PHONE_TYPE_COLUMN_INDEX);
- info.label = phonesCursor.getString(LABEL_COLUMN_INDEX);
- info.number = phonesCursor.getString(MATCHED_NUMBER_COLUMN_INDEX);
- info.normalizedNumber =
- phonesCursor.getString(NORMALIZED_NUMBER_COLUMN_INDEX);
+ info.personId = phonesCursor.getLong(PhoneQuery.PERSON_ID);
+ info.name = phonesCursor.getString(PhoneQuery.NAME);
+ info.type = phonesCursor.getInt(PhoneQuery.PHONE_TYPE);
+ info.label = phonesCursor.getString(PhoneQuery.LABEL);
+ info.number = phonesCursor
+ .getString(PhoneQuery.MATCHED_NUMBER);
+ info.normalizedNumber = phonesCursor
+ .getString(PhoneQuery.NORMALIZED_NUMBER);
infoUpdated = true;
}
@@ -452,6 +453,7 @@
* Handles requests for contact name and number type
* @see java.lang.Runnable#run()
*/
+ @Override
public void run() {
boolean needNotify = false;
while (!mDone) {
@@ -490,11 +492,11 @@
CharArrayBuffer currentValue = mBuffer1;
CharArrayBuffer value = mBuffer2;
cursor.moveToFirst();
- cursor.copyStringToBuffer(NUMBER_COLUMN_INDEX, currentValue);
- int currentCallType = cursor.getInt(CALL_TYPE_COLUMN_INDEX);
+ cursor.copyStringToBuffer(CallLogQuery.NUMBER, currentValue);
+ int currentCallType = cursor.getInt(CallLogQuery.CALL_TYPE);
for (int i = 1; i < count; i++) {
cursor.moveToNext();
- cursor.copyStringToBuffer(NUMBER_COLUMN_INDEX, value);
+ cursor.copyStringToBuffer(CallLogQuery.NUMBER, value);
boolean sameNumber = equalPhoneNumbers(value, currentValue);
// Group adjacent calls with the same number. Make an exception
@@ -520,7 +522,7 @@
if (sameNumber && currentCallType == Calls.MISSED_TYPE) {
currentCallType = 0; // "not a missed call"
} else {
- currentCallType = cursor.getInt(CALL_TYPE_COLUMN_INDEX);
+ currentCallType = cursor.getInt(CallLogQuery.CALL_TYPE);
}
}
}
@@ -539,16 +541,16 @@
@Override
- protected View newStandAloneView(Context context, ViewGroup parent) {
+ public View newStandAloneView(Context context, ViewGroup parent) {
LayoutInflater inflater =
(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- View view = inflater.inflate(R.layout.recent_calls_list_item, parent, false);
+ View view = inflater.inflate(R.layout.call_log_list_item, parent, false);
findAndCacheViews(view);
return view;
}
@Override
- protected void bindStandAloneView(View view, Context context, Cursor cursor) {
+ public void bindStandAloneView(View view, Context context, Cursor cursor) {
bindView(context, view, cursor);
}
@@ -556,7 +558,7 @@
protected View newChildView(Context context, ViewGroup parent) {
LayoutInflater inflater =
(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- View view = inflater.inflate(R.layout.recent_calls_list_child_item, parent, false);
+ View view = inflater.inflate(R.layout.call_log_list_child_item, parent, false);
findAndCacheViews(view);
return view;
}
@@ -570,7 +572,7 @@
protected View newGroupView(Context context, ViewGroup parent) {
LayoutInflater inflater =
(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- View view = inflater.inflate(R.layout.recent_calls_list_group_item, parent, false);
+ View view = inflater.inflate(R.layout.call_log_list_group_item, parent, false);
findAndCacheViews(view);
return view;
}
@@ -578,7 +580,7 @@
@Override
protected void bindGroupView(View view, Context context, Cursor cursor, int groupSize,
boolean expanded) {
- final RecentCallsListItemViews views = (RecentCallsListItemViews) view.getTag();
+ final CallLogListItemViews views = (CallLogListItemViews) view.getTag();
int groupIndicator = expanded
? com.android.internal.R.drawable.expander_ic_maximized
: com.android.internal.R.drawable.expander_ic_minimized;
@@ -590,7 +592,7 @@
private void findAndCacheViews(View view) {
// Get the views to bind to
- RecentCallsListItemViews views = new RecentCallsListItemViews();
+ CallLogListItemViews views = new CallLogListItemViews();
views.line1View = (TextView) view.findViewById(R.id.line1);
views.labelView = (TextView) view.findViewById(R.id.label);
views.numberView = (TextView) view.findViewById(R.id.number);
@@ -604,14 +606,14 @@
}
public void bindView(Context context, View view, Cursor c) {
- final RecentCallsListItemViews views = (RecentCallsListItemViews) view.getTag();
+ final CallLogListItemViews views = (CallLogListItemViews) view.getTag();
- String number = c.getString(NUMBER_COLUMN_INDEX);
+ String number = c.getString(CallLogQuery.NUMBER);
String formattedNumber = null;
- String callerName = c.getString(CALLER_NAME_COLUMN_INDEX);
- int callerNumberType = c.getInt(CALLER_NUMBERTYPE_COLUMN_INDEX);
- String callerNumberLabel = c.getString(CALLER_NUMBERLABEL_COLUMN_INDEX);
- String countryIso = c.getString(COUNTRY_ISO_COLUMN_INDEX);
+ String callerName = c.getString(CallLogQuery.CALLER_NAME);
+ int callerNumberType = c.getInt(CallLogQuery.CALLER_NUMBERTYPE);
+ String callerNumberLabel = c.getString(CallLogQuery.CALLER_NUMBERLABEL);
+ String countryIso = c.getString(CallLogQuery.COUNTRY_ISO);
// Store away the number so we can call it directly if you click on the call icon
views.callView.setTag(number);
@@ -728,7 +730,7 @@
views.labelView.setVisibility(View.GONE);
}
- long date = c.getLong(DATE_COLUMN_INDEX);
+ long date = c.getLong(CallLogQuery.DATE);
// Set the date/time field by mixing relative and absolute times.
int flags = DateUtils.FORMAT_ABBREV_RELATIVE;
@@ -737,7 +739,7 @@
System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS, flags));
if (views.iconView != null) {
- int type = c.getInt(CALL_TYPE_COLUMN_INDEX);
+ int type = c.getInt(CallLogQuery.CALL_TYPE);
// Set the icon
switch (type) {
case Calls.INCOMING_TYPE:
@@ -764,7 +766,7 @@
}
private static final class QueryHandler extends AsyncQueryHandler {
- private final WeakReference<RecentCallsListActivity> mActivity;
+ private final WeakReference<CallLogFragment> mFragment;
/**
* Simple handler that wraps background calls to catch
@@ -796,25 +798,26 @@
return new CatchingWorkerHandler(looper);
}
- public QueryHandler(Context context) {
- super(context.getContentResolver());
- mActivity = new WeakReference<RecentCallsListActivity>(
- (RecentCallsListActivity) context);
+ public QueryHandler(CallLogFragment fragment) {
+ super(fragment.getActivity().getContentResolver());
+ mFragment = new WeakReference<CallLogFragment>(fragment);
}
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
- final RecentCallsListActivity activity = mActivity.get();
- if (activity != null && !activity.isFinishing()) {
- final RecentCallsListActivity.RecentCallsAdapter callsAdapter = activity.mAdapter;
+ final CallLogFragment fragment = mFragment.get();
+ if (fragment != null && fragment.getActivity() != null &&
+ !fragment.getActivity().isFinishing()) {
+ final CallLogFragment.CallLogAdapter callsAdapter = fragment.mAdapter;
callsAdapter.setLoading(false);
callsAdapter.changeCursor(cursor);
- if (activity.mScrollToTop) {
- if (activity.mList.getFirstVisiblePosition() > 5) {
- activity.mList.setSelection(5);
+ if (fragment.mScrollToTop) {
+ final ListView listView = fragment.getListView();
+ if (listView.getFirstVisiblePosition() > 5) {
+ listView.setSelection(5);
}
- activity.mList.smoothScrollToPosition(0);
- activity.mScrollToTop = false;
+ listView.smoothScrollToPosition(0);
+ fragment.mScrollToTop = false;
}
} else {
cursor.close();
@@ -823,33 +826,39 @@
}
@Override
- protected void onCreate(Bundle state) {
+ public void onCreate(Bundle state) {
super.onCreate(state);
- setContentView(R.layout.recent_calls);
-
- // Typing here goes to the dialer
- setDefaultKeyMode(DEFAULT_KEYS_DIALER);
-
- mAdapter = new RecentCallsAdapter();
- getListView().setOnCreateContextMenuListener(this);
- setListAdapter(mAdapter);
-
- mVoiceMailNumber = ((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE))
- .getVoiceMailNumber();
+ mVoiceMailNumber = ((TelephonyManager) getActivity().getSystemService(
+ Context.TELEPHONY_SERVICE)).getVoiceMailNumber();
mQueryHandler = new QueryHandler(this);
- mCurrentCountryIso = ContactsUtils.getCurrentCountryIso(this);
+ mCurrentCountryIso = ContactsUtils.getCurrentCountryIso(getActivity());
+
+ setHasOptionsMenu(true);
}
@Override
- protected void onStart() {
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+ return inflater.inflate(R.layout.call_log_fragment, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ getListView().setOnCreateContextMenuListener(this);
+ mAdapter = new CallLogAdapter();
+ setListAdapter(mAdapter);
+ }
+
+ @Override
+ public void onStart() {
mScrollToTop = true;
super.onStart();
}
@Override
- protected void onResume() {
+ public void onResume() {
// The adapter caches looked up numbers, clear it so they will get
// looked up again.
if (mAdapter != null) {
@@ -865,7 +874,7 @@
}
@Override
- protected void onPause() {
+ public void onPause() {
super.onPause();
// Kill the requests thread
@@ -873,34 +882,12 @@
}
@Override
- protected void onDestroy() {
+ public void onDestroy() {
super.onDestroy();
mAdapter.stopRequestProcessing();
mAdapter.changeCursor(null);
}
- @Override
- public void onWindowFocusChanged(boolean hasFocus) {
- super.onWindowFocusChanged(hasFocus);
-
- // Clear notifications only when window gains focus. This activity won't
- // immediately receive focus if the keyguard screen is above it.
- if (hasFocus) {
- try {
- ITelephony iTelephony =
- ITelephony.Stub.asInterface(ServiceManager.getService("phone"));
- if (iTelephony != null) {
- iTelephony.cancelMissedCallsNotification();
- } else {
- Log.w(TAG, "Telephony service is null, can't call " +
- "cancelMissedCallsNotification");
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to clear missed calls notification due to remote exception");
- }
- }
- }
-
/**
* Format the given phone number
*
@@ -944,14 +931,14 @@
// Cancel any pending queries
mQueryHandler.cancelOperation(QUERY_TOKEN);
mQueryHandler.startQuery(QUERY_TOKEN, null, Calls.CONTENT_URI,
- CALL_LOG_PROJECTION, null, null, Calls.DEFAULT_SORT_ORDER);
+ CallLogQuery._PROJECTION, null, null, Calls.DEFAULT_SORT_ORDER);
}
@Override
- public boolean onCreateOptionsMenu(Menu menu) {
- menu.add(0, MENU_ITEM_DELETE_ALL, 0, R.string.recentCalls_deleteAll)
- .setIcon(android.R.drawable.ic_menu_close_clear_cancel);
- return true;
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ menu.add(0, OptionsMenuItems.DELETE_ALL, 0, R.string.recentCalls_deleteAll).setIcon(
+ android.R.drawable.ic_menu_close_clear_cancel);
}
@Override
@@ -966,7 +953,7 @@
Cursor cursor = (Cursor) mAdapter.getItem(menuInfo.position);
- String number = cursor.getString(NUMBER_COLUMN_INDEX);
+ String number = cursor.getString(CallLogQuery.NUMBER);
Uri numberUri = null;
boolean isVoicemail = false;
boolean isSipNumber = false;
@@ -1033,45 +1020,14 @@
menu.add(0, 0, 0, R.string.recentCalls_addToContact)
.setIntent(intent);
}
- menu.add(0, MENU_ITEM_DELETE, 0, R.string.recentCalls_removeFromRecentList);
- }
-
- @Override
- protected Dialog onCreateDialog(int id, Bundle args) {
- switch (id) {
- case DIALOG_CONFIRM_DELETE_ALL:
- return new AlertDialog.Builder(this)
- .setTitle(R.string.clearCallLogConfirmation_title)
- .setIconAttribute(android.R.attr.alertDialogIcon)
- .setMessage(R.string.clearCallLogConfirmation)
- .setNegativeButton(android.R.string.cancel, null)
- .setPositiveButton(android.R.string.ok, new OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- getContentResolver().delete(Calls.CONTENT_URI, null, null);
- // TODO The change notification should do this automatically, but it
- // isn't working right now. Remove this when the change notification
- // is working properly.
- startQuery();
- }
- })
- .setCancelable(false)
- .create();
- }
- return null;
+ menu.add(0, MenuItems.DELETE, 0, R.string.recentCalls_removeFromRecentList);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case MENU_ITEM_DELETE_ALL: {
- showDialog(DIALOG_CONFIRM_DELETE_ALL);
- return true;
- }
-
- case MENU_ITEM_VIEW_CONTACTS: {
- Intent intent = new Intent(Intent.ACTION_VIEW, Contacts.CONTENT_URI);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent);
+ case OptionsMenuItems.DELETE_ALL: {
+ ClearCallLogDialog.show(getFragmentManager());
return true;
}
}
@@ -1090,7 +1046,7 @@
}
switch (item.getItemId()) {
- case MENU_ITEM_DELETE: {
+ case MenuItems.DELETE: {
Cursor cursor = (Cursor)mAdapter.getItem(menuInfo.position);
int groupSize = 1;
if (mAdapter.isGroupHeader(menuInfo.position)) {
@@ -1103,58 +1059,17 @@
sb.append(",");
cursor.moveToNext();
}
- long id = cursor.getLong(ID_COLUMN_INDEX);
+ long id = cursor.getLong(CallLogQuery.ID);
sb.append(id);
}
- getContentResolver().delete(Calls.CONTENT_URI, Calls._ID + " IN (" + sb + ")",
- null);
+ getActivity().getContentResolver().delete(Calls.CONTENT_URI,
+ Calls._ID + " IN (" + sb + ")", null);
}
}
return super.onContextItemSelected(item);
}
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_CALL: {
- long callPressDiff = SystemClock.uptimeMillis() - event.getDownTime();
- if (callPressDiff >= ViewConfiguration.getLongPressTimeout()) {
- // Launch voice dialer
- Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- startActivity(intent);
- } catch (ActivityNotFoundException e) {
- }
- return true;
- }
- }
- }
- return super.onKeyDown(keyCode, event);
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_CALL:
- try {
- ITelephony phone = ITelephony.Stub.asInterface(
- ServiceManager.checkService("phone"));
- if (phone != null && !phone.isIdle()) {
- // Let the super class handle it
- break;
- }
- } catch (RemoteException re) {
- // Fall through and try to call the contact
- }
-
- callEntry(getListView().getSelectedItemPosition());
- return true;
- }
- return super.onKeyUp(keyCode, event);
- }
-
/*
* Get the number from the Contacts, if available, since sometimes
* the number provided by caller id may not be formatted properly
@@ -1172,14 +1087,12 @@
matchingNumber = ci.number;
} else {
try {
- Cursor phonesCursor =
- RecentCallsListActivity.this.getContentResolver().query(
- Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
- number),
- PHONES_PROJECTION, null, null, null);
+ Cursor phonesCursor = getActivity().getContentResolver().query(
+ Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number),
+ PhoneQuery._PROJECTION, null, null, null);
if (phonesCursor != null) {
if (phonesCursor.moveToFirst()) {
- matchingNumber = phonesCursor.getString(MATCHED_NUMBER_COLUMN_INDEX);
+ matchingNumber = phonesCursor.getString(PhoneQuery.MATCHED_NUMBER);
}
phonesCursor.close();
}
@@ -1195,7 +1108,8 @@
return number;
}
- private void callEntry(int position) {
+ public void callSelectedEntry() {
+ int position = getListView().getSelectedItemPosition();
if (position < 0) {
// In touch mode you may often not have something selected, so
// just call the first entry to make sure that [send] [send] calls the
@@ -1204,7 +1118,7 @@
}
final Cursor cursor = (Cursor)mAdapter.getItem(position);
if (cursor != null) {
- String number = cursor.getString(NUMBER_COLUMN_INDEX);
+ String number = cursor.getString(CallLogQuery.NUMBER);
if (TextUtils.isEmpty(number)
|| number.equals(CallerInfo.UNKNOWN_NUMBER)
|| number.equals(CallerInfo.PRIVATE_NUMBER)
@@ -1220,7 +1134,7 @@
} else {
// We're calling a regular PSTN phone number.
// Construct a tel: URI, but do some other possible cleanup first.
- int callType = cursor.getInt(CALL_TYPE_COLUMN_INDEX);
+ int callType = cursor.getInt(CallLogQuery.CALL_TYPE);
if (!number.startsWith("+") &&
(callType == Calls.INCOMING_TYPE
|| callType == Calls.MISSED_TYPE)) {
@@ -1237,23 +1151,21 @@
}
@Override
- protected void onListItemClick(ListView l, View v, int position, long id) {
+ public void onListItemClick(ListView l, View v, int position, long id) {
if (mAdapter.isGroupHeader(position)) {
mAdapter.toggleGroup(position);
} else {
- Intent intent = new Intent(this, CallDetailActivity.class);
+ Intent intent = new Intent(getActivity(), CallDetailActivity.class);
intent.setData(ContentUris.withAppendedId(CallLog.Calls.CONTENT_URI, id));
startActivity(intent);
}
}
- @Override
- public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
- boolean globalSearch) {
- if (globalSearch) {
- super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
- } else {
- ContactsSearchManager.startSearch(this, initialQuery);
- }
+ public CallLogAdapter getAdapter() {
+ return mAdapter;
+ }
+
+ public String getVoiceMailNumber() {
+ return mVoiceMailNumber;
}
}
diff --git a/src/com/android/contacts/calllog/ClearCallLogDialog.java b/src/com/android/contacts/calllog/ClearCallLogDialog.java
new file mode 100644
index 0000000..426732a
--- /dev/null
+++ b/src/com/android/contacts/calllog/ClearCallLogDialog.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.calllog;
+
+import com.android.contacts.R;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.app.ProgressDialog;
+import android.content.ContentResolver;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.provider.CallLog.Calls;
+
+/**
+ * Dialog that clears the call log after confirming with the user
+ */
+public class ClearCallLogDialog extends DialogFragment {
+ /** Preferred way to show this dialog */
+ public static void show(FragmentManager fragmentManager) {
+ ClearCallLogDialog dialog = new ClearCallLogDialog();
+ dialog.show(fragmentManager, "deleteCallLog");
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final ContentResolver resolver = getActivity().getContentResolver();
+ final OnClickListener okListener = new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ final ProgressDialog progressDialog = ProgressDialog.show(getActivity(),
+ getString(R.string.clearCallLogProgress_title),
+ "", true, false);
+ final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ resolver.delete(Calls.CONTENT_URI, null, null);
+ return null;
+ }
+ @Override
+ protected void onPostExecute(Void result) {
+ progressDialog.dismiss();
+ }
+ };
+ // TODO: Once we have the API, we should configure this ProgressDialog
+ // to only show up after a certain time (e.g. 150ms)
+ progressDialog.show();
+ task.execute();
+ }
+ };
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(R.string.clearCallLogConfirmation_title)
+ .setIconAttribute(android.R.attr.alertDialogIcon)
+ .setMessage(R.string.clearCallLogConfirmation)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok, okListener)
+ .setCancelable(true)
+ .create();
+ }
+}
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index 5dde900..f3a4805 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -27,9 +27,9 @@
import com.android.contacts.TypePrecedence;
import com.android.contacts.editor.SelectAccountDialogFragment;
import com.android.contacts.model.AccountType;
-import com.android.contacts.model.AccountType.DataKind;
import com.android.contacts.model.AccountType.EditType;
import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.DataKind;
import com.android.contacts.util.Constants;
import com.android.contacts.util.DataStatus;
import com.android.contacts.util.DateUtils;
@@ -60,6 +60,7 @@
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Event;
import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
@@ -163,34 +164,26 @@
* A list of distinct contact IDs included in the current contact.
*/
private ArrayList<Long> mRawContactIds = new ArrayList<Long>();
- private ArrayList<ViewEntry> mPhoneEntries = new ArrayList<ViewEntry>();
- private ArrayList<ViewEntry> mSmsEntries = new ArrayList<ViewEntry>();
- private ArrayList<ViewEntry> mEmailEntries = new ArrayList<ViewEntry>();
- private ArrayList<ViewEntry> mPostalEntries = new ArrayList<ViewEntry>();
- private ArrayList<ViewEntry> mImEntries = new ArrayList<ViewEntry>();
- private ArrayList<ViewEntry> mNicknameEntries = new ArrayList<ViewEntry>();
- private ArrayList<ViewEntry> mGroupEntries = new ArrayList<ViewEntry>();
- private ArrayList<ViewEntry> mRelationEntries = new ArrayList<ViewEntry>();
- private ArrayList<ViewEntry> mOtherEntries = new ArrayList<ViewEntry>();
- private ArrayList<ArrayList<ViewEntry>> mSections = new ArrayList<ArrayList<ViewEntry>>();
+ private ArrayList<DetailViewEntry> mPhoneEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mSmsEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mEmailEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mPostalEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mImEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mNicknameEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mGroupEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mRelationEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mNoteEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mWebsiteEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mSipEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mEventEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mOtherEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<ViewEntry> mAllEntries = new ArrayList<ViewEntry>();
private LayoutInflater mInflater;
private boolean mTransitionAnimationRequested;
public ContactDetailFragment() {
// Explicit constructor for inflation
-
- // Build the list of sections. The order they're added to mSections dictates the
- // order they are displayed in the list.
- mSections.add(mPhoneEntries);
- mSections.add(mSmsEntries);
- mSections.add(mEmailEntries);
- mSections.add(mImEntries);
- mSections.add(mPostalEntries);
- mSections.add(mNicknameEntries);
- mSections.add(mOtherEntries);
- mSections.add(mRelationEntries);
- mSections.add(mGroupEntries);
}
@Override
@@ -222,9 +215,6 @@
mInflater = inflater;
- mHeaderView = (ContactDetailHeaderView) mView.findViewById(R.id.contact_header_widget);
- mHeaderView.setListener(mHeaderViewListener);
-
mListView = (ListView) mView.findViewById(android.R.id.list);
mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY);
mListView.setOnItemClickListener(this);
@@ -303,19 +293,22 @@
return;
}
- // Set the header
- mHeaderView.loadData(mContactData);
+ // Clear old header
+ mHeaderView = null;
// Build up the contact entries
buildEntries();
- // Collapse similar data items in select sections.
+ // Collapse similar data items for select {@link DataKind}s.
Collapser.collapseList(mPhoneEntries);
Collapser.collapseList(mSmsEntries);
Collapser.collapseList(mEmailEntries);
Collapser.collapseList(mPostalEntries);
Collapser.collapseList(mImEntries);
+ // Make one aggregated list of all entries for display to the user.
+ flattenAllLists();
+
if (mAdapter == null) {
mAdapter = new ViewAdapter();
mListView.setAdapter(mAdapter);
@@ -349,10 +342,7 @@
mHasSip = PhoneCapabilityTester.isSipPhone(mContext);
// Clear out the old entries
- final int numSections = mSections.size();
- for (int i = 0; i < numSections; i++) {
- mSections.get(i).clear();
- }
+ mAllEntries.clear();
mRawContactIds.clear();
@@ -408,8 +398,9 @@
accountType, mimeType);
if (kind == null) continue;
- final ViewEntry entry = ViewEntry.fromValues(mContext, mimeType, kind, dataId,
- entryValues);
+ final DetailViewEntry entry = DetailViewEntry.fromValues(mContext, mimeType, kind,
+ dataId, entryValues, mContactData.isDirectoryEntry(),
+ mContactData.getDirectoryId());
final boolean hasData = !TextUtils.isEmpty(entry.data);
Integer superPrimary = entryValues.getAsInteger(Data.IS_SUPER_PRIMARY);
@@ -444,7 +435,6 @@
entry.actionIcon = -1;
}
-
// Remember super-primary phone
if (isSuperPrimary) mPrimaryPhoneUri = entry.uri;
@@ -463,8 +453,9 @@
final String imMime = Im.CONTENT_ITEM_TYPE;
final DataKind imKind = accountTypes.getKindOrFallback(accountType,
imMime);
- final ViewEntry imEntry = ViewEntry.fromValues(mContext,
- imMime, imKind, dataId, entryValues);
+ final DetailViewEntry imEntry = DetailViewEntry.fromValues(mContext, imMime,
+ imKind, dataId, entryValues, mContactData.isDirectoryEntry(),
+ mContactData.getDirectoryId());
buildImActions(imEntry, entryValues);
imEntry.applyStatus(status, false);
mImEntries.add(imEntry);
@@ -472,7 +463,8 @@
} else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
// Build postal entries
entry.maxLines = 4;
- entry.intent = new Intent(Intent.ACTION_VIEW, entry.uri);
+ entry.intent = new Intent(
+ Intent.ACTION_VIEW, Uri.parse("geo:0,0?q=" + Uri.encode(entry.data)));
mPostalEntries.add(entry);
} else if (Im.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
// Build IM entries
@@ -504,7 +496,7 @@
// Build note entries
entry.uri = null;
entry.maxLines = 100;
- mOtherEntries.add(entry);
+ mNoteEntries.add(entry);
} else if (Website.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
// Build Website entries
entry.uri = null;
@@ -516,7 +508,7 @@
} catch (ParseException e) {
Log.e(TAG, "Couldn't parse website: " + entry.data);
}
- mOtherEntries.add(entry);
+ mWebsiteEntries.add(entry);
} else if (SipAddress.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
// Build SipAddress entries
entry.uri = null;
@@ -528,17 +520,17 @@
entry.intent = null;
entry.actionIcon = -1;
}
- mOtherEntries.add(entry);
- // TODO: Consider moving the SipAddress into its own
- // section (rather than lumping it in with mOtherEntries)
- // so that we can reposition it right under the phone number.
+ mSipEntries.add(entry);
+ // TODO: Now that SipAddress is in its own list of entries
+ // (instead of grouped in mOtherEntries), consider
+ // repositioning it right under the phone number.
// (Then, we'd also update FallbackAccountType.java to set
// secondary=false for this field, and tweak the weight
// of its DataKind.)
} else if (Event.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
entry.data = DateUtils.formatDate(mContext, entry.data);
entry.uri = null;
- mOtherEntries.add(entry);
+ mEventEntries.add(entry);
} else if (Relation.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
entry.intent = new Intent(Intent.ACTION_SEARCH);
entry.intent.putExtra(SearchManager.QUERY, entry.data);
@@ -546,7 +538,8 @@
mRelationEntries.add(entry);
} else {
// Handle showing custom rows
- entry.intent = new Intent(Intent.ACTION_VIEW, entry.uri);
+ entry.intent = new Intent(Intent.ACTION_VIEW);
+ entry.intent.setDataAndType(entry.uri, entry.mimetype);
// Use social summary when requested by external source
final DataStatus status = mContactData.getStatuses().get(entry.id);
@@ -563,7 +556,7 @@
}
if (!groups.isEmpty()) {
- ViewEntry entry = new ViewEntry();
+ DetailViewEntry entry = new DetailViewEntry();
Collections.sort(groups);
StringBuilder sb = new StringBuilder();
int size = groups.size();
@@ -581,6 +574,49 @@
}
/**
+ * Collapse all contact detail entries into one aggregated list with a {@link HeaderViewEntry}
+ * at the top.
+ */
+ private void flattenAllLists() {
+ // All contacts should have a header view (even if there is no data for the contact).
+ mAllEntries.add(new HeaderViewEntry());
+
+ flattenList(mPhoneEntries);
+ flattenList(mSmsEntries);
+ flattenList(mEmailEntries);
+ flattenList(mImEntries);
+ flattenList(mPostalEntries);
+ flattenList(mNicknameEntries);
+ flattenList(mNoteEntries);
+ flattenList(mWebsiteEntries);
+ flattenList(mSipEntries);
+ flattenList(mEventEntries);
+ flattenList(mOtherEntries);
+ flattenList(mRelationEntries);
+ flattenList(mGroupEntries);
+ }
+
+ /**
+ * Iterate through {@link DetailViewEntry} in the given list and add it to a list of all
+ * entries. Add a {@link SeparatorViewEntry} at the end if the length of the list was not 0.
+ * Clear the original list.
+ */
+ private void flattenList(ArrayList<DetailViewEntry> entries) {
+ int count = entries.size();
+
+ for (int i = 0; i < count; i++) {
+ mAllEntries.add(entries.get(i));
+ }
+
+ if (count > 0) {
+ mAllEntries.add(new SeparatorViewEntry());
+ }
+
+ // Clear old list because it's not needed anymore.
+ entries.clear();
+ }
+
+ /**
* Maps group ID to the corresponding group name, collapses all synonymous groups.
* Ignores default groups (e.g. My Contacts) and favorites groups.
*/
@@ -617,7 +653,7 @@
* {@link Email} row. If the result is non-null, it either contains one or two Intents
* (e.g. [Text, Videochat] or just [Text])
*/
- public static void buildImActions(ViewEntry entry, ContentValues values) {
+ public static void buildImActions(DetailViewEntry entry, ContentValues values) {
final boolean isEmail = Email.CONTENT_ITEM_TYPE.equals(values.getAsString(Data.MIMETYPE));
if (!isEmail && !isProtocolValid(values)) {
@@ -686,15 +722,65 @@
}
/**
- * A basic structure with the data for a contact entry in the list.
+ * Base class for an item in the {@link ViewAdapter} list of data, which is
+ * supplied to the {@link ListView}.
*/
- static class ViewEntry implements Collapsible<ViewEntry> {
+ static class ViewEntry {
+ private final int viewTypeForAdapter;
+ protected long id = -1;
+ /** Whether or not the entry can be focused on or not. */
+ protected boolean isEnabled = false;
+
+ ViewEntry(int viewType) {
+ viewTypeForAdapter = viewType;
+ }
+
+ int getViewType() {
+ return viewTypeForAdapter;
+ }
+
+ long getId() {
+ return id;
+ }
+
+ boolean isEnabled(){
+ return isEnabled;
+ }
+ }
+
+ /**
+ * Header item in the {@link ViewAdapter} list of data.
+ */
+ static class HeaderViewEntry extends ViewEntry {
+
+ HeaderViewEntry() {
+ super(ViewAdapter.VIEW_TYPE_HEADER_ENTRY);
+ }
+
+ }
+
+ /**
+ * Separator between items of the same {@link DataKind} in the
+ * {@link ViewAdapter} list of data.
+ */
+ static class SeparatorViewEntry extends ViewEntry {
+
+ SeparatorViewEntry() {
+ super(ViewAdapter.VIEW_TYPE_SEPARATOR_ENTRY);
+ }
+
+ }
+
+ /**
+ * An item with a single detail for a contact in the {@link ViewAdapter}
+ * list of data.
+ */
+ static class DetailViewEntry extends ViewEntry implements Collapsible<DetailViewEntry> {
public int type = -1;
public String kind;
public String typeString;
public String data;
public Uri uri;
- public long id = 0;
public int maxLines = 1;
public String mimetype;
@@ -713,18 +799,24 @@
public CharSequence footerLine = null;
- ViewEntry() {
+ DetailViewEntry() {
+ super(ViewAdapter.VIEW_TYPE_DETAIL_ENTRY);
+ isEnabled = true;
}
/**
- * Build new {@link ViewEntry} and populate from the given values.
+ * Build new {@link DetailViewEntry} and populate from the given values.
*/
- public static ViewEntry fromValues(Context context, String mimeType, DataKind kind,
- long dataId, ContentValues values) {
- final ViewEntry entry = new ViewEntry();
- entry.context = context;
+ public static DetailViewEntry fromValues(Context context, String mimeType, DataKind kind,
+ long dataId, ContentValues values, boolean isDirectoryEntry, long directoryId) {
+ final DetailViewEntry entry = new DetailViewEntry();
entry.id = dataId;
+ entry.context = context;
entry.uri = ContentUris.withAppendedId(Data.CONTENT_URI, entry.id);
+ if (isDirectoryEntry) {
+ entry.uri = entry.uri.buildUpon().appendQueryParameter(
+ ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId)).build();
+ }
entry.mimetype = mimeType;
entry.kind = (kind.titleRes == -1 || kind.titleRes == 0) ? ""
: context.getString(kind.titleRes);
@@ -762,13 +854,13 @@
}
/**
- * Apply given {@link DataStatus} values over this {@link ViewEntry}
+ * Apply given {@link DataStatus} values over this {@link DetailViewEntry}
*
* @param fillData When true, the given status replaces {@link #data}
* and {@link #footerLine}. Otherwise only {@link #presence}
* is updated.
*/
- public ViewEntry applyStatus(DataStatus status, boolean fillData) {
+ public DetailViewEntry applyStatus(DataStatus status, boolean fillData) {
presence = status.getPresence();
if (fillData && status.isValid()) {
this.data = status.getStatus().toString();
@@ -779,7 +871,7 @@
}
@Override
- public boolean collapseWith(ViewEntry entry) {
+ public boolean collapseWith(DetailViewEntry entry) {
// assert equal collapse keys
if (!shouldCollapseWith(entry)) {
return false;
@@ -808,13 +900,13 @@
// uri, and contactdId, shouldn't make a difference. Just keep the original.
// Keep track of all the ids that have been collapsed with this one.
- ids.add(entry.id);
+ ids.add(entry.getId());
collapseCount++;
return true;
}
@Override
- public boolean shouldCollapseWith(ViewEntry entry) {
+ public boolean shouldCollapseWith(DetailViewEntry entry) {
if (entry == null) {
return false;
}
@@ -837,23 +929,64 @@
/** Cache of the children views of a row */
private static class ViewCache {
- public View kindDivider;
- public View inKindDivider;
- public View lineBelowLast;
public TextView kind;
public TextView type;
public TextView data;
public TextView footer;
- public ImageView actionIcon;
public ImageView presenceIcon;
public ImageView secondaryActionButton;
+ public View secondaryActionButtonContainer;
public View secondaryActionDivider;
}
private final class ViewAdapter extends BaseAdapter {
+
+ public static final int VIEW_TYPE_DETAIL_ENTRY = 0;
+ public static final int VIEW_TYPE_HEADER_ENTRY = 1;
+ public static final int VIEW_TYPE_SEPARATOR_ENTRY = 2;
+ private static final int VIEW_TYPE_COUNT = 3;
+
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- final ViewEntry entry = getEntry(position);
+ switch (getItemViewType(position)) {
+ case VIEW_TYPE_HEADER_ENTRY:
+ return getHeaderEntryView(convertView, parent);
+ case VIEW_TYPE_SEPARATOR_ENTRY:
+ return getSeparatorEntryView(convertView, parent);
+ case VIEW_TYPE_DETAIL_ENTRY:
+ return getDetailEntryView(position, convertView, parent);
+ default:
+ throw new IllegalStateException("Invalid view type ID " +
+ getItemViewType(position));
+ }
+ }
+
+ private View getHeaderEntryView(View convertView, ViewGroup parent) {
+ // We don't want to rely on the recycled header view because it may
+ // have been left over from a previously viewed contact (since we
+ // reuse the adapter), so we would have to bind the data to the
+ // header each time. However, since there is only 1 header per list,
+ // just hold onto the original header view for this contact and
+ // return that each time.
+ if (mHeaderView != null) {
+ return mHeaderView;
+ }
+ mHeaderView = (ContactDetailHeaderView) mInflater.inflate(
+ R.layout.contact_detail_header_view_list_item, parent, false);
+ mHeaderView.setListener(mHeaderViewListener);
+ mHeaderView.loadData(mContactData);
+ return mHeaderView;
+ }
+
+ private View getSeparatorEntryView(View convertView, ViewGroup parent) {
+ if (convertView != null) {
+ return convertView;
+ }
+ return mInflater.inflate(R.layout.contact_detail_separator_list_item, parent, false);
+ }
+
+ private View getDetailEntryView(int position, View convertView, ViewGroup parent) {
+ final DetailViewEntry entry = (DetailViewEntry) getItem(position);
final View v;
final ViewCache viewCache;
@@ -868,46 +1001,49 @@
// Cache the children
viewCache = new ViewCache();
viewCache.kind = (TextView) v.findViewById(R.id.kind);
- viewCache.kindDivider = v.findViewById(R.id.kind_divider);
- viewCache.lineBelowLast = v.findViewById(R.id.line_below_last);
- viewCache.inKindDivider = v.findViewById(R.id.in_kind_divider);
viewCache.type = (TextView) v.findViewById(R.id.type);
viewCache.data = (TextView) v.findViewById(R.id.data);
viewCache.footer = (TextView) v.findViewById(R.id.footer);
- viewCache.actionIcon = (ImageView) v.findViewById(R.id.action_icon);
viewCache.presenceIcon = (ImageView) v.findViewById(R.id.presence_icon);
viewCache.secondaryActionButton = (ImageView) v.findViewById(
R.id.secondary_action_button);
- viewCache.secondaryActionButton.setOnClickListener(mSecondaryActionClickListener);
+ viewCache.secondaryActionButtonContainer = v.findViewById(
+ R.id.secondary_action_button_container);
+ viewCache.secondaryActionButtonContainer.setOnClickListener(
+ mSecondaryActionClickListener);
viewCache.secondaryActionDivider = v.findViewById(R.id.divider);
v.setTag(viewCache);
}
- final ViewEntry previousEntry = position == 0 ? null : getEntry(position - 1);
- final boolean isFirstOfItsKind =
- previousEntry == null ? true : !previousEntry.kind.equals(entry.kind);
- final boolean isLast = position == getCount() - 1;
+ final ViewEntry previousEntry = position == 0 ? null : getItem(position - 1);
+ final boolean isFirstOfItsKind = (previousEntry == null) ? true :
+ (previousEntry.getViewType() != VIEW_TYPE_DETAIL_ENTRY);
// Bind the data to the view
- bindView(v, entry, isFirstOfItsKind, isLast);
+ bindView(v, entry, isFirstOfItsKind);
return v;
}
- protected void bindView(View view, ViewEntry entry, boolean isFirstOfItsKind,
- boolean isLast) {
+ private void bindView(View view, DetailViewEntry entry, boolean isFirstOfItsKind) {
final Resources resources = mContext.getResources();
ViewCache views = (ViewCache) view.getTag();
- views.kind.setText(isFirstOfItsKind ? entry.kind : "");
- views.kindDivider.setVisibility(isFirstOfItsKind ? View.VISIBLE : View.GONE);
- views.inKindDivider.setVisibility(isFirstOfItsKind ? View.GONE : View.VISIBLE);
- if (views.lineBelowLast != null) {
- views.lineBelowLast.setVisibility(isLast ? View.VISIBLE : View.GONE);
+ if (isFirstOfItsKind) {
+ views.kind.setText(entry.kind != null ? entry.kind.toUpperCase() : "");
+ views.kind.setVisibility(View.VISIBLE);
+ } else {
+ views.kind.setVisibility(View.GONE);
}
- views.type.setText(entry.typeString);
- views.type.setVisibility(
- TextUtils.isEmpty(entry.typeString) ? View.GONE : View.VISIBLE);
+ if (!TextUtils.isEmpty(entry.typeString)) {
+ views.type.setText(entry.typeString.toUpperCase());
+ views.type.setVisibility(View.VISIBLE);
+ if (isFirstOfItsKind) {
+ views.kind.setVisibility(View.GONE);
+ }
+ } else {
+ views.type.setVisibility(View.GONE);
+ }
views.data.setText(entry.data);
setMaxLines(views.data, entry.maxLines);
@@ -920,24 +1056,6 @@
views.footer.setVisibility(View.GONE);
}
- // Set the action icon
- final ImageView action = views.actionIcon;
- if (entry.actionIcon != -1) {
- Drawable actionIcon;
- if (entry.resPackageName != null) {
- // Load external resources through PackageManager
- actionIcon = mContext.getPackageManager().getDrawable(entry.resPackageName,
- entry.actionIcon, null);
- } else {
- actionIcon = resources.getDrawable(entry.actionIcon);
- }
- action.setImageDrawable(actionIcon);
- action.setVisibility(View.VISIBLE);
- } else {
- // Things should still line up as if there was an icon, so make it invisible
- action.setVisibility(View.INVISIBLE);
- }
-
// Set the presence icon
final Drawable presenceIcon = ContactPresenceIconUtil.getPresenceIcon(
mContext, entry.presence);
@@ -964,11 +1082,11 @@
if (entry.secondaryIntent != null && secondaryActionIcon != null) {
secondaryActionView.setImageDrawable(secondaryActionIcon);
- secondaryActionView.setTag(entry);
- secondaryActionView.setVisibility(View.VISIBLE);
+ views.secondaryActionButtonContainer.setTag(entry);
+ views.secondaryActionButtonContainer.setVisibility(View.VISIBLE);
views.secondaryActionDivider.setVisibility(View.VISIBLE);
} else {
- secondaryActionView.setVisibility(View.GONE);
+ views.secondaryActionButtonContainer.setVisibility(View.GONE);
views.secondaryActionDivider.setVisibility(View.GONE);
}
}
@@ -990,8 +1108,9 @@
if (mListener == null) return;
if (v == null) return;
final ViewEntry entry = (ViewEntry) v.getTag();
- if (entry == null) return;
- final Intent intent = entry.secondaryIntent;
+ if (entry == null || !(entry instanceof DetailViewEntry)) return;
+ final DetailViewEntry detailViewEntry = (DetailViewEntry) entry;
+ final Intent intent = detailViewEntry.secondaryIntent;
if (intent == null) return;
mListener.onItemClicked(intent);
}
@@ -999,40 +1118,42 @@
@Override
public int getCount() {
- int count = 0;
- final int numSections = mSections.size();
- for (int i = 0; i < numSections; i++) {
- final ArrayList<ViewEntry> section = mSections.get(i);
- count += section.size();
- }
- return count;
+ return mAllEntries.size();
}
@Override
- public Object getItem(int position) {
- return getEntry(position);
+ public ViewEntry getItem(int position) {
+ return mAllEntries.get(position);
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return mAllEntries.get(position).getViewType();
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return VIEW_TYPE_COUNT;
}
@Override
public long getItemId(int position) {
- final ViewEntry entry = getEntry(position);
+ final ViewEntry entry = mAllEntries.get(position);
if (entry != null) {
- return entry.id;
+ return entry.getId();
}
return -1;
}
- private ViewEntry getEntry(int position) {
- final int numSections = mSections.size();
- for (int i = 0; i < numSections; i++) {
- final ArrayList<ViewEntry> section = mSections.get(i);
- final int sectionSize = section.size();
- if (position < sectionSize) {
- return section.get(position);
- }
- position -= sectionSize;
- }
- return null;
+ @Override
+ public boolean areAllItemsEnabled() {
+ // Header will always be an item that is not enabled.
+ return false;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return getItem(position).isEnabled();
}
}
@@ -1165,7 +1286,7 @@
}
@Override
- public void onAccountChosen(Account account) {
+ public void onAccountChosen(int requestCode, Account account) {
createCopy(account);
}
@@ -1178,9 +1299,9 @@
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (mListener == null) return;
- final ViewEntry entry = mAdapter.getEntry(position);
- if (entry == null) return;
- final Intent intent = entry.intent;
+ final ViewEntry entry = mAdapter.getItem(position);
+ if (entry == null || !(entry instanceof DetailViewEntry)) return;
+ final Intent intent = ((DetailViewEntry) entry).intent;
if (intent == null) return;
mListener.onItemClicked(intent);
}
@@ -1216,7 +1337,7 @@
int index = mListView.getSelectedItemPosition();
if (index != -1) {
- final ViewEntry entry = mAdapter.getEntry(index);
+ final DetailViewEntry entry = (DetailViewEntry) mAdapter.getItem(index);
if (entry != null && entry.intent != null &&
entry.intent.getAction() == Intent.ACTION_CALL_PRIVILEGED) {
mContext.startActivity(entry.intent);
@@ -1254,7 +1375,7 @@
@Override
public void onLoadFinished(Loader<ContactLoader.Result> loader, ContactLoader.Result data) {
- if (!((ContactLoader)loader).getLookupUri().equals(mLookupUri)) {
+ if (!mLookupUri.equals(data.getUri())) {
return;
}
diff --git a/src/com/android/contacts/detail/ContactDetailHeaderView.java b/src/com/android/contacts/detail/ContactDetailHeaderView.java
index 4b211b6..795ed62 100644
--- a/src/com/android/contacts/detail/ContactDetailHeaderView.java
+++ b/src/com/android/contacts/detail/ContactDetailHeaderView.java
@@ -20,6 +20,8 @@
import com.android.contacts.ContactLoader.Result;
import com.android.contacts.ContactSaveService;
import com.android.contacts.R;
+import com.android.contacts.format.FormatUtils;
+import com.android.contacts.preference.ContactsPreferences;
import com.android.contacts.util.ContactBadgeUtil;
import android.content.ClipData;
@@ -31,10 +33,13 @@
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Typeface;
import android.net.Uri;
+import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Organization;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.DisplayNameSources;
+import android.text.Spanned;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -122,7 +127,8 @@
public void loadData(ContactLoader.Result contactData) {
mContactUri = contactData.getLookupUri();
- setDisplayName(contactData.getDisplayName(), contactData.getPhoneticName());
+ setDisplayName(contactData.getDisplayName(), contactData.getAltDisplayName(),
+ contactData.getPhoneticName());
setCompany(contactData);
if (contactData.isLoadingPhoto()) {
setPhoto(null, false);
@@ -188,8 +194,38 @@
/**
* Set the display name and phonetic name to show in the header.
*/
- private void setDisplayName(CharSequence displayName, CharSequence phoneticName) {
- mDisplayNameView.setText(displayName);
+ private void setDisplayName(CharSequence displayName, CharSequence altDisplayName,
+ CharSequence phoneticName) {
+
+ // Check the preference for display name ordering, and bold the contact's first name if
+ // possible.
+ ContactsPreferences prefs = new ContactsPreferences(getContext());
+ CharSequence styledName = "";
+ if (!TextUtils.isEmpty(displayName) && !TextUtils.isEmpty(altDisplayName)) {
+ if (prefs.getDisplayOrder() == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) {
+ int overlapPoint = FormatUtils.overlapPoint(
+ displayName.toString(), altDisplayName.toString());
+ if (overlapPoint > 0) {
+ styledName = FormatUtils.applyStyleToSpan(Typeface.BOLD,
+ displayName, 0, overlapPoint, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ } else {
+ styledName = displayName;
+ }
+ } else {
+ // Displaying alternate display name.
+ int overlapPoint = FormatUtils.overlapPoint(
+ altDisplayName.toString(), displayName.toString());
+ if (overlapPoint > 0) {
+ styledName = FormatUtils.applyStyleToSpan(Typeface.BOLD,
+ altDisplayName, overlapPoint, altDisplayName.length(),
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ } else {
+ styledName = altDisplayName;
+ }
+ }
+ }
+ mDisplayNameView.setText(styledName);
+
if (TextUtils.isEmpty(phoneticName)) {
mPhoneticNameView.setVisibility(View.GONE);
} else {
diff --git a/src/com/android/contacts/TwelveKeyDialer.java b/src/com/android/contacts/dialpad/DialpadFragment.java
similarity index 85%
rename from src/com/android/contacts/TwelveKeyDialer.java
rename to src/com/android/contacts/dialpad/DialpadFragment.java
index b93375c..58ffb9e 100644
--- a/src/com/android/contacts/TwelveKeyDialer.java
+++ b/src/com/android/contacts/dialpad/DialpadFragment.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * 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.
@@ -14,17 +14,20 @@
* limitations under the License.
*/
-package com.android.contacts;
+package com.android.contacts.dialpad;
+import com.android.contacts.ContactsUtils;
+import com.android.contacts.R;
+import com.android.contacts.SpecialCharSequenceMgr;
+import com.android.contacts.activities.DialtactsActivity;
import com.android.internal.telephony.ITelephony;
import com.android.phone.CallLogAsync;
import com.android.phone.HapticFeedback;
import android.app.Activity;
-import android.content.ActivityNotFoundException;
+import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
@@ -36,12 +39,11 @@
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.provider.Settings;
+import android.provider.Contacts.Intents.Insert;
import android.provider.Contacts.People;
import android.provider.Contacts.Phones;
import android.provider.Contacts.PhonesColumns;
-import android.provider.Contacts.Intents.Insert;
+import android.provider.Settings;
import android.telephony.PhoneNumberFormattingTextWatcher;
import android.telephony.PhoneNumberUtils;
import android.telephony.PhoneStateListener;
@@ -54,12 +56,10 @@
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
+import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.ViewGroup;
-import android.view.Window;
-import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.EditText;
@@ -68,14 +68,15 @@
import android.widget.TextView;
/**
- * Dialer activity that displays the typical twelve key interface.
+ * Fragment that displays a twelve-key phone dialpad.
*/
-@SuppressWarnings("deprecation")
-public class TwelveKeyDialer extends Activity implements View.OnClickListener,
+public class DialpadFragment extends Fragment
+ implements View.OnClickListener,
View.OnLongClickListener, View.OnKeyListener,
AdapterView.OnItemClickListener, TextWatcher {
+ private static final String TAG = "DialpadFragment";
+
private static final String EMPTY_NUMBER = "";
- private static final String TAG = "TwelveKeyDialer";
/** The length of DTMF tones in milliseconds */
private static final int TONE_LENGTH_MS = 150;
@@ -173,7 +174,7 @@
}
public void afterTextChanged(Editable input) {
- if (SpecialCharSequenceMgr.handleChars(this, input.toString(), mDigits)) {
+ if (SpecialCharSequenceMgr.handleChars(getActivity(), input.toString(), mDigits)) {
// A special sequence was entered, clear the digits
mDigits.getText().clear();
}
@@ -189,24 +190,31 @@
}
@Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
+ public void onCreate(Bundle state) {
+ super.onCreate(state);
- mCurrentCountryIso = ContactsUtils.getCurrentCountryIso(this);
- Resources r = getResources();
- // Do not show title in the case the device is in carmode.
- if ((r.getConfiguration().uiMode & Configuration.UI_MODE_TYPE_MASK) ==
- Configuration.UI_MODE_TYPE_CAR) {
- requestWindowFeature(Window.FEATURE_NO_TITLE);
+ mCurrentCountryIso = ContactsUtils.getCurrentCountryIso(getActivity());
+
+ try {
+ mHaptic.init(getActivity(),
+ getResources().getBoolean(R.bool.config_enable_dialer_key_vibration));
+ } catch (Resources.NotFoundException nfe) {
+ Log.e(TAG, "Vibrate control bool missing.", nfe);
}
- // Set the content view
- setContentView(getContentViewResource());
+
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+ View fragmentView = inflater.inflate(R.layout.dialpad_fragment, container, false);
// Load up the resources for the text field.
+ Resources r = getResources();
mDigitsBackground = r.getDrawable(R.drawable.btn_dial_textfield_active);
mDigitsEmptyBackground = r.getDrawable(R.drawable.btn_dial_textfield);
- mDigits = (EditText) findViewById(R.id.digits);
+ mDigits = (EditText) fragmentView.findViewById(R.id.digits);
mDigits.setKeyListener(DialerKeyListener.getInstance());
mDigits.setOnClickListener(this);
mDigits.setOnKeyListener(this);
@@ -214,12 +222,12 @@
maybeAddNumberFormatting();
// Check for the presence of the keypad
- View view = findViewById(R.id.one);
- if (view != null) {
- setupKeypad();
+ View oneButton = fragmentView.findViewById(R.id.one);
+ if (oneButton != null) {
+ setupKeypad(fragmentView);
}
- mVoicemailDialAndDeleteRow = findViewById(R.id.voicemailAndDialAndDelete);
+ mVoicemailDialAndDeleteRow = fragmentView.findViewById(R.id.voicemailAndDialAndDelete);
initVoicemailButton();
@@ -233,12 +241,11 @@
mDialButton = null;
}
- view = mVoicemailDialAndDeleteRow.findViewById(R.id.deleteButton);
- view.setOnClickListener(this);
- view.setOnLongClickListener(this);
- mDelete = view;
+ mDelete = mVoicemailDialAndDeleteRow.findViewById(R.id.deleteButton);
+ mDelete.setOnClickListener(this);
+ mDelete.setOnLongClickListener(this);
- mDialpad = findViewById(R.id.dialpad); // This is null in landscape mode.
+ mDialpad = fragmentView.findViewById(R.id.dialpad); // This is null in landscape mode.
// In landscape we put the keyboard in phone mode.
// In portrait we prevent the soft keyboard to show since the
@@ -250,47 +257,42 @@
}
// Set up the "dialpad chooser" UI; see showDialpadChooser().
- mDialpadChooser = (ListView) findViewById(R.id.dialpadChooser);
+ mDialpadChooser = (ListView) fragmentView.findViewById(R.id.dialpadChooser);
mDialpadChooser.setOnItemClickListener(this);
- if (!resolveIntent() && icicle != null) {
- super.onRestoreInstanceState(icicle);
- }
-
- try {
- mHaptic.init(this, r.getBoolean(R.bool.config_enable_dialer_key_vibration));
- } catch (Resources.NotFoundException nfe) {
- Log.e(TAG, "Vibrate control bool missing.", nfe);
- }
-
+ return fragmentView;
}
- @Override
- protected void onRestoreInstanceState(Bundle icicle) {
- // Do nothing, state is restored in onCreate() if needed
+ public EditText getDigitsWidget() {
+ return mDigits;
}
- protected void maybeAddNumberFormatting() {
+ private void maybeAddNumberFormatting() {
mDigits.addTextChangedListener(new PhoneNumberFormattingTextWatcher(mCurrentCountryIso));
}
/**
- * Overridden by subclasses to control the resource used by the content view.
+ * Handles the intent that launched us.
+ *
+ * We can be launched either with ACTION_DIAL or ACTION_VIEW (which
+ * may include a phone number to pre-load), or ACTION_MAIN (which just
+ * brings up a blank dialpad).
+ *
+ * @return true IFF the current intent has the DialtactsActivity.EXTRA_IGNORE_STATE
+ * extra set to true, which indicates (to our container) that we should ignore
+ * any possible saved state, and instead reset our state based on the parent's
+ * intent.
*/
- protected int getContentViewResource() {
- return R.layout.twelve_key_dialer;
- }
-
- private boolean resolveIntent() {
+ public boolean resolveIntent() {
boolean ignoreState = false;
// Find the proper intent
final Intent intent;
- if (isChild()) {
- intent = getParent().getIntent();
+ if (getActivity().isChild()) {
+ intent = getActivity().getParent().getIntent();
ignoreState = intent.getBooleanExtra(DialtactsActivity.EXTRA_IGNORE_STATE, false);
} else {
- intent = getIntent();
+ intent = getActivity().getIntent();
}
// Log.i(TAG, "==> resolveIntent(): intent: " + intent);
@@ -317,7 +319,7 @@
if (People.CONTENT_ITEM_TYPE.equals(type)
|| Phones.CONTENT_ITEM_TYPE.equals(type)) {
// Query the phone number
- Cursor c = getContentResolver().query(intent.getData(),
+ Cursor c = getActivity().getContentResolver().query(intent.getData(),
new String[] {PhonesColumns.NUMBER, PhonesColumns.NUMBER_KEY},
null, null, null);
if (c != null) {
@@ -363,7 +365,7 @@
return ignoreState;
}
- protected void setFormattedDigits(String data, String normalizedNumber) {
+ private void setFormattedDigits(String data, String normalizedNumber) {
// strip the non-dialable numbers out of the data string.
String dialString = PhoneNumberUtils.extractNetworkPortion(data);
dialString =
@@ -377,16 +379,32 @@
}
}
- @Override
- protected void onNewIntent(Intent newIntent) {
- setIntent(newIntent);
- resolveIntent();
+ private void setupKeypad(View fragmentView) {
+ // Setup the listeners for the buttons
+ View view = fragmentView.findViewById(R.id.one);
+ view.setOnClickListener(this);
+ view.setOnLongClickListener(this);
+
+ fragmentView.findViewById(R.id.two).setOnClickListener(this);
+ fragmentView.findViewById(R.id.three).setOnClickListener(this);
+ fragmentView.findViewById(R.id.four).setOnClickListener(this);
+ fragmentView.findViewById(R.id.five).setOnClickListener(this);
+ fragmentView.findViewById(R.id.six).setOnClickListener(this);
+ fragmentView.findViewById(R.id.seven).setOnClickListener(this);
+ fragmentView.findViewById(R.id.eight).setOnClickListener(this);
+ fragmentView.findViewById(R.id.nine).setOnClickListener(this);
+ fragmentView.findViewById(R.id.star).setOnClickListener(this);
+
+ view = fragmentView.findViewById(R.id.zero);
+ view.setOnClickListener(this);
+ view.setOnLongClickListener(this);
+
+ fragmentView.findViewById(R.id.pound).setOnClickListener(this);
}
- @Override
- protected void onPostCreate(Bundle savedInstanceState) {
- super.onPostCreate(savedInstanceState);
-
+ // Do some stuff that needs to happen only once, but which we
+ // can't do directly from onCreate().
+ public void onPostCreate() {
// This can't be done in onCreate(), since the auto-restoring of the digits
// will play DTMF tones for all the old digits if it is when onRestoreSavedInstanceState()
// is called. This method will be called every time the activity is created, and
@@ -394,31 +412,8 @@
mDigits.addTextChangedListener(this);
}
- private void setupKeypad() {
- // Setup the listeners for the buttons
- View view = findViewById(R.id.one);
- view.setOnClickListener(this);
- view.setOnLongClickListener(this);
-
- findViewById(R.id.two).setOnClickListener(this);
- findViewById(R.id.three).setOnClickListener(this);
- findViewById(R.id.four).setOnClickListener(this);
- findViewById(R.id.five).setOnClickListener(this);
- findViewById(R.id.six).setOnClickListener(this);
- findViewById(R.id.seven).setOnClickListener(this);
- findViewById(R.id.eight).setOnClickListener(this);
- findViewById(R.id.nine).setOnClickListener(this);
- findViewById(R.id.star).setOnClickListener(this);
-
- view = findViewById(R.id.zero);
- view.setOnClickListener(this);
- view.setOnLongClickListener(this);
-
- findViewById(R.id.pound).setOnClickListener(this);
- }
-
@Override
- protected void onResume() {
+ public void onResume() {
super.onResume();
// Query the last dialed number. Do it first because hitting
@@ -426,7 +421,7 @@
queryLastOutgoingCall();
// retrieve the DTMF tone play back setting.
- mDTMFToneEnabled = Settings.System.getInt(getContentResolver(),
+ mDTMFToneEnabled = Settings.System.getInt(getActivity().getContentResolver(),
Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1;
// Retrieve the haptic feedback setting.
@@ -434,14 +429,14 @@
// if the mToneGenerator creation fails, just continue without it. It is
// a local audio signal, and is not as important as the dtmf tone itself.
- synchronized(mToneGeneratorLock) {
+ synchronized (mToneGeneratorLock) {
if (mToneGenerator == null) {
try {
// we want the user to be able to control the volume of the dial tones
// outside of a call, so we use the stream type that is also mapped to the
// volume control keys for this activity
mToneGenerator = new ToneGenerator(DIAL_TONE_STREAM_TYPE, TONE_RELATIVE_VOLUME);
- setVolumeControlStream(DIAL_TONE_STREAM_TYPE);
+ getActivity().setVolumeControlStream(DIAL_TONE_STREAM_TYPE);
} catch (RuntimeException e) {
Log.w(TAG, "Exception caught while creating local tone generator: " + e);
mToneGenerator = null;
@@ -449,7 +444,7 @@
}
}
- Activity parent = getParent();
+ Activity parent = getActivity().getParent();
// See if we were invoked with a DIAL intent. If we were, fill in the appropriate
// digits in the dialer field.
if (parent != null && parent instanceof DialtactsActivity) {
@@ -462,7 +457,8 @@
// While we're in the foreground, listen for phone state changes,
// purely so that we can take down the "dialpad chooser" if the
// phone becomes idle while the chooser UI is visible.
- TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
+ TelephonyManager telephonyManager =
+ (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
// Potentially show hint text in the mDigits field when the user
@@ -489,27 +485,15 @@
}
@Override
- public void onWindowFocusChanged(boolean hasFocus) {
- if (hasFocus) {
- // Hide soft keyboard, if visible (it's fugly over button dialer).
- // The only known case where this will be true is when launching the dialer with
- // ACTION_DIAL via a soft keyboard. we dismiss it here because we don't
- // have a window token yet in onCreate / onNewIntent
- InputMethodManager inputMethodManager = (InputMethodManager)
- getSystemService(Context.INPUT_METHOD_SERVICE);
- inputMethodManager.hideSoftInputFromWindow(mDigits.getWindowToken(), 0);
- }
- }
-
- @Override
- protected void onPause() {
+ public void onPause() {
super.onPause();
// Stop listening for phone state changes.
- TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
+ TelephonyManager telephonyManager =
+ (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
- synchronized(mToneGeneratorLock) {
+ synchronized (mToneGeneratorLock) {
if (mToneGenerator != null) {
mToneGenerator.release();
mToneGenerator = null;
@@ -521,22 +505,25 @@
}
@Override
- public boolean onCreateOptionsMenu(Menu menu) {
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+
mAddToContactMenuItem = menu.add(0, MENU_ADD_CONTACTS, 0, R.string.recentCalls_addToContact)
.setIcon(android.R.drawable.ic_menu_add);
m2SecPauseMenuItem = menu.add(0, MENU_2S_PAUSE, 0, R.string.add_2sec_pause)
.setIcon(R.drawable.ic_menu_2sec_pause);
mWaitMenuItem = menu.add(0, MENU_WAIT, 0, R.string.add_wait)
.setIcon(R.drawable.ic_menu_wait);
- return true;
}
@Override
- public boolean onPrepareOptionsMenu(Menu menu) {
+ public void onPrepareOptionsMenu(Menu menu) {
+ // If we have not been inflated yet, there is no menu
+ if (mDialpadChooser == null) return;
+
// We never show a menu if the "choose dialpad" UI is up.
- if (dialpadChooserVisible()) {
- return false;
- }
+ // Otherwise the menu is allowed (see onPrepareOptionsMenu() below.)
+ if (!dialpadChooserVisible()) return;
if (isDigitsEmpty()) {
mAddToContactMenuItem.setVisible(false);
@@ -587,46 +574,6 @@
strLength, strDigits));
}
}
- return true;
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_CALL: {
- long callPressDiff = SystemClock.uptimeMillis() - event.getDownTime();
- if (callPressDiff >= ViewConfiguration.getLongPressTimeout()) {
- // Launch voice dialer
- Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- startActivity(intent);
- } catch (ActivityNotFoundException e) {
- }
- }
- return true;
- }
- case KeyEvent.KEYCODE_1: {
- long timeDiff = SystemClock.uptimeMillis() - event.getDownTime();
- if (timeDiff >= ViewConfiguration.getLongPressTimeout()) {
- // Long press detected, call voice mail
- callVoicemail();
- }
- return true;
- }
- }
- return super.onKeyDown(keyCode, event);
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_CALL: {
- dialButtonPressed();
- return true;
- }
- }
- return super.onKeyUp(keyCode, event);
}
private void keyPressed(int keyCode) {
@@ -647,6 +594,7 @@
return false;
}
+ @Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.one: {
@@ -759,10 +707,10 @@
return false;
}
- void callVoicemail() {
+ public void callVoicemail() {
startActivity(newVoicemailIntent());
mDigits.getText().clear(); // TODO: Fix bug 1745781
- finish();
+ getActivity().finish();
}
/**
@@ -784,7 +732,7 @@
* user needs to press the dial button again, to dial it (general
* case described above).
*/
- void dialButtonPressed() {
+ public void dialButtonPressed() {
if (isDigitsEmpty()) { // No number entered.
if (phoneIsCdma() && phoneIsOffhook()) {
// This is really CDMA specific. On GSM is it possible
@@ -809,11 +757,10 @@
startActivity(newDialNumberIntent(number));
mDigits.getText().clear(); // TODO: Fix bug 1745781
- finish();
+ getActivity().finish();
}
}
-
/**
* Plays the specified tone for TONE_LENGTH_MS milliseconds.
*
@@ -834,16 +781,17 @@
// call, rather than keeping a local flag that's updated in
// onResume(), since it's possible to toggle silent mode without
// leaving the current activity (via the ENDCALL-longpress menu.)
- AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+ AudioManager audioManager =
+ (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
int ringerMode = audioManager.getRingerMode();
if ((ringerMode == AudioManager.RINGER_MODE_SILENT)
|| (ringerMode == AudioManager.RINGER_MODE_VIBRATE)) {
return;
}
- synchronized(mToneGeneratorLock) {
+ synchronized (mToneGeneratorLock) {
if (mToneGenerator == null) {
- Log.w(TAG, "playTone: mToneGenerator == null, tone: "+tone);
+ Log.w(TAG, "playTone: mToneGenerator == null, tone: " + tone);
return;
}
@@ -879,7 +827,7 @@
// Instantiate the DialpadChooserAdapter and hook it up to the
// ListView. We do this only once.
if (mDialpadChooserAdapter == null) {
- mDialpadChooserAdapter = new DialpadChooserAdapter(this);
+ mDialpadChooserAdapter = new DialpadChooserAdapter(getActivity());
mDialpadChooser.setAdapter(mDialpadChooserAdapter);
}
} else {
@@ -1049,7 +997,7 @@
// the dialpad chooser is up. In this case we can't show the
// InCallScreen, and there's no point staying here in the Dialer,
// so we just take the user back where he came from...)
- finish();
+ getActivity().finish();
}
/**
@@ -1097,7 +1045,6 @@
return phoneOffhook;
}
-
/**
* Returns true whenever any one of the options from the menu is selected.
* Code changes to support dialpad options
@@ -1131,7 +1078,7 @@
selectionEnd = Math.max(anchor, point);
Editable digits = mDigits.getText();
- if (selectionStart != -1 ) {
+ if (selectionStart != -1) {
if (selectionStart == selectionEnd) {
// then there is no selection. So insert the pause at this
// position and update the mDigits.
@@ -1171,7 +1118,6 @@
mDelete.setEnabled(digitsNotEmpty);
}
-
/**
* Check if voicemail is enabled/accessible.
*/
@@ -1202,7 +1148,7 @@
if (start > digits.length()) return false;
// preceding char is ';', so visible should be false
- if (digits.charAt(start-1) == ';') return false;
+ if (digits.charAt(start - 1) == ';') return false;
// next char is ';', so visible should be false
if ((digits.length() > start) && (digits.charAt(start) == ';')) return false;
@@ -1212,7 +1158,7 @@
// In this case we need to just check for ';' preceding to start
// or next to end
- if (digits.charAt(start-1) == ';') return false;
+ if (digits.charAt(start - 1) == ';') return false;
}
return true;
}
@@ -1234,7 +1180,7 @@
mLastNumberDialed = EMPTY_NUMBER;
CallLogAsync.GetLastOutgoingCallArgs lastCallArgs =
new CallLogAsync.GetLastOutgoingCallArgs(
- this,
+ getActivity(),
new CallLogAsync.OnLastOutgoingCallComplete() {
public void lastOutgoingCall(String number) {
// TODO: Filter out emergency numbers if
@@ -1247,16 +1193,6 @@
mCallLog.getLastOutgoingCall(lastCallArgs);
}
- @Override
- public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
- boolean globalSearch) {
- if (globalSearch) {
- super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
- } else {
- ContactsSearchManager.startSearch(this, initialQuery);
- }
- }
-
// Helpers for the call intents.
private Intent newVoicemailIntent() {
final Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
diff --git a/src/com/android/contacts/editor/AggregationSuggestionView.java b/src/com/android/contacts/editor/AggregationSuggestionView.java
index 5403731..af8e7f8 100644
--- a/src/com/android/contacts/editor/AggregationSuggestionView.java
+++ b/src/com/android/contacts/editor/AggregationSuggestionView.java
@@ -136,7 +136,7 @@
@Override
public boolean performClick() {
- if (mListener != null) {
+ if (mListener != null && isEnabled()) {
if (canEditSuggestedContact()) {
mListener.onEditAction(Contacts.getLookupUri(mContactId, mLookupKey));
} else {
diff --git a/src/com/android/contacts/editor/BaseRawContactEditorView.java b/src/com/android/contacts/editor/BaseRawContactEditorView.java
index 49ca863..38636f7 100644
--- a/src/com/android/contacts/editor/BaseRawContactEditorView.java
+++ b/src/com/android/contacts/editor/BaseRawContactEditorView.java
@@ -49,7 +49,6 @@
private PhotoEditorView mPhoto;
private boolean mHasPhotoEditor = false;
- private View mHeader;
private View mBody;
private View mDivider;
@@ -67,15 +66,8 @@
protected void onFinishInflate() {
super.onFinishInflate();
- mHeader = findViewById(R.id.header);
mBody = findViewById(R.id.body);
mDivider = findViewById(R.id.divider);
- mHeader.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- setExpanded(!mExpanded);
- }
- });
mPhoto = (PhotoEditorView)findViewById(R.id.edit_photo);
mPhoto.setEnabled(isEnabled());
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index b117d77..96d5843 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -31,8 +31,7 @@
import com.android.contacts.model.EntityDeltaList;
import com.android.contacts.model.EntityModifier;
import com.android.contacts.model.GoogleAccountType;
-import com.android.contacts.util.EmptyService;
-import com.android.contacts.util.WeakAsyncTask;
+import com.android.contacts.util.AccountsListAdapter;
import android.accounts.Account;
import android.app.Activity;
@@ -43,9 +42,6 @@
import android.app.LoaderManager;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.ActivityNotFoundException;
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
@@ -54,7 +50,6 @@
import android.content.Entity;
import android.content.Intent;
import android.content.Loader;
-import android.content.OperationApplicationException;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Rect;
@@ -62,22 +57,18 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
-import android.os.RemoteException;
import android.os.SystemClock;
-import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Event;
import android.provider.ContactsContract.CommonDataKinds.Note;
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.CommonDataKinds.Website;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Intents;
import android.provider.ContactsContract.RawContacts;
import android.provider.MediaStore;
-import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -88,7 +79,9 @@
import android.view.ViewGroup.LayoutParams;
import android.view.ViewGroup.MarginLayoutParams;
import android.view.ViewStub;
+import android.widget.AdapterView;
import android.widget.LinearLayout;
+import android.widget.ListPopupWindow;
import android.widget.Toast;
import java.io.File;
@@ -100,7 +93,7 @@
import java.util.List;
public class ContactEditorFragment extends Fragment implements
- SplitContactConfirmationDialogFragment.Listener, SelectAccountDialogFragment.Listener,
+ SplitContactConfirmationDialogFragment.Listener,
AggregationSuggestionEngine.Listener, AggregationSuggestionView.Listener,
ExternalRawContactEditorView.Listener {
@@ -115,10 +108,12 @@
private static final String KEY_RAW_CONTACT_ID_REQUESTING_PHOTO = "photorequester";
private static final String KEY_VIEW_ID_GENERATOR = "viewidgenerator";
private static final String KEY_CURRENT_PHOTO_FILE = "currentphotofile";
- private static final String KEY_QUERY_SELECTION = "queryselection";
private static final String KEY_CONTACT_ID_FOR_JOIN = "contactidforjoin";
private static final String KEY_SHOW_JOIN_SUGGESTIONS = "showJoinSuggestions";
private static final String KEY_ENABLED = "enabled";
+ private static final String KEY_STATUS = "status";
+
+ public static final String SAVE_MODE_EXTRA_KEY = "saveMode";
/**
* An intent extra that forces the editor to add the edited contact
@@ -168,15 +163,23 @@
public static final int EDITING = 1;
/**
- * The data is currently being saved. This is used to prevent more auto-saves (they shouldn't
- * overlap)
+ * The data is currently being saved. This is used to prevent more
+ * auto-saves (they shouldn't overlap)
*/
public static final int SAVING = 2;
/**
- * Prevents any more savings (this is used if Save/Close or Revert was executed by the user)
+ * Prevents any more saves. This is used if in the following cases:
+ * - After Save/Close
+ * - After Revert
+ * - After the user has accepted an edit suggestion
*/
public static final int CLOSING = 3;
+
+ /**
+ * Prevents saving while running a child activity.
+ */
+ public static final int SUB_ACTIVITY = 4;
}
private static final int REQUEST_CODE_JOIN = 0;
@@ -215,8 +218,6 @@
private Bundle mIntentExtras;
private Listener mListener;
- private String mQuerySelection;
-
private long mContactIdForJoin;
private LinearLayout mContent;
@@ -227,7 +228,6 @@
private long mLoaderStartTime;
private int mStatus;
- private boolean mSaveOnStop = true;
private AggregationSuggestionEngine mAggregationSuggestionEngine;
private long mAggregationSuggestionsRawContactId;
@@ -236,6 +236,7 @@
private boolean mAutoAddToDefaultGroup;
private boolean mEnabled = true;
+ private boolean mRequestFocus;
public ContactEditorFragment() {
}
@@ -249,6 +250,7 @@
mContent.getChildAt(i).setEnabled(enabled);
}
}
+ setAggregationSuggestionViewEnabled(enabled);
final Activity activity = getActivity();
if (activity != null) activity.invalidateOptionsMenu();
}
@@ -268,7 +270,7 @@
}
// If anything was left unsaved, save it now but keep the editor open.
- if (!getActivity().isChangingConfigurations() && mStatus == Status.EDITING && mSaveOnStop) {
+ if (!getActivity().isChangingConfigurations() && mStatus == Status.EDITING) {
save(SaveMode.RELOAD);
}
}
@@ -314,8 +316,10 @@
} else {
// No Account specified. Let the user choose
// Load Accounts async so that we can present them
- selectAccountAndCreateContact();
+ createContact();
}
+ } else if (ContactEditorActivity.ACTION_SAVE_COMPLETED.equals(mAction)) {
+ // do nothing
} else throw new IllegalArgumentException("Unknown Action String " + mAction +
". Only support " + Intent.ACTION_EDIT + " or " + Intent.ACTION_INSERT);
}
@@ -323,7 +327,6 @@
@Override
public void onStart() {
- mSaveOnStop = true;
getLoaderManager().initLoader(LOADER_GROUPS, null, mGroupLoaderListener);
super.onStart();
}
@@ -364,11 +367,10 @@
if (fileName != null) {
mCurrentPhotoFile = new File(fileName);
}
- mQuerySelection = savedState.getString(KEY_QUERY_SELECTION);
mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN);
mAggregationSuggestionsRawContactId = savedState.getLong(KEY_SHOW_JOIN_SUGGESTIONS);
mEnabled = savedState.getBoolean(KEY_ENABLED);
- mStatus = Status.EDITING;
+ mStatus = savedState.getInt(KEY_STATUS);
}
}
@@ -409,22 +411,12 @@
private void bindEditorsForExistingContact(ContactLoader.Result data) {
setEnabled(true);
- // Build Filter mQuerySelection
- final ArrayList<Entity> entities = data.getEntities();
- final StringBuilder sb = new StringBuilder(RawContacts._ID + " IN(");
- final int count = entities.size();
- for (int i = 0; i < count; i++) {
- if (i > 0) {
- sb.append(',');
- }
- sb.append(entities.get(i).getEntityValues().get(RawContacts._ID));
- }
- sb.append(")");
- mQuerySelection = sb.toString();
- mState = EntityDeltaList.fromIterator(entities.iterator());
+ mState = EntityDeltaList.fromIterator(data.getEntities().iterator());
setIntentExtras(mIntentExtras);
mIntentExtras = null;
+ mRequestFocus = true;
+
bindEditors();
}
@@ -448,7 +440,11 @@
}
}
- private void selectAccountAndCreateContact() {
+ /**
+ * Shows the account creation screen. An account associated with the contact is automatically
+ * selected. If there's no available account, device-local contact should be created.
+ */
+ private void createContact() {
final ArrayList<Account> accounts =
AccountTypeManager.getInstance(mContext).getAccounts(true);
// No Accounts available. Create a phone-local contact.
@@ -457,21 +453,16 @@
return; // Don't show a dialog.
}
- // In the common case of a single account being writable, auto-select
- // it without showing a dialog.
- if (accounts.size() == 1) {
- createContact(accounts.get(0));
- return; // Don't show a dialog.
- }
-
- final SelectAccountDialogFragment dialog = new SelectAccountDialogFragment();
- dialog.setTargetFragment(this, 0);
- dialog.show(getFragmentManager(), SelectAccountDialogFragment.TAG);
+ // We have an account switcher in "create-account" screen, so don't need to ask a user to
+ // select an account here.
+ createContact(accounts.get(0));
}
+
/**
- * @param account may be null to signal a device-local contact should
- * be created.
+ * Shows account creation screen associated with a given account.
+ *
+ * @param account may be null to signal a device-local contact should be created.
*/
private void createContact(Account account) {
final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
@@ -487,29 +478,66 @@
}
}
+ /**
+ * Removes a current editor ({@link #mState}) and rebinds new editor for a new account.
+ * Some of old data are reused with new restriction enforced by the new account.
+ *
+ * @param oldState Old data being editted.
+ * @param oldAccount Old account associated with oldState.
+ * @param newAccount New account to be used.
+ */
+ private void rebindEditorsForNewContact(
+ EntityDelta oldState, Account oldAccount, Account newAccount) {
+ AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
+ AccountType oldAccountType = accountTypes.getAccountType(oldAccount.type);
+ AccountType newAccountType = accountTypes.getAccountType(newAccount.type);
+
+ if (newAccountType.getCreateContactActivityClassName() != null) {
+ Log.w(TAG, "external activity called in rebind situation");
+ if (mListener != null) {
+ mListener.onCustomCreateContactActivityRequested(newAccount, mIntentExtras);
+ }
+ } else {
+ mState = null;
+ bindEditorsForNewContact(newAccount, newAccountType, oldState, oldAccountType);
+ }
+ }
+
private void bindEditorsForNewContact(Account account, final AccountType accountType) {
+ bindEditorsForNewContact(account, accountType, null, null);
+ }
+
+ private void bindEditorsForNewContact(Account newAccount, final AccountType newAccountType,
+ EntityDelta oldState, AccountType oldAccountType) {
+ mStatus = Status.EDITING;
+
final ContentValues values = new ContentValues();
- if (account != null) {
- values.put(RawContacts.ACCOUNT_NAME, account.name);
- values.put(RawContacts.ACCOUNT_TYPE, account.type);
+ if (newAccount != null) {
+ values.put(RawContacts.ACCOUNT_NAME, newAccount.name);
+ values.put(RawContacts.ACCOUNT_TYPE, newAccount.type);
} else {
values.putNull(RawContacts.ACCOUNT_NAME);
values.putNull(RawContacts.ACCOUNT_TYPE);
}
- // Parse any values from incoming intent
EntityDelta insert = new EntityDelta(ValuesDelta.fromAfter(values));
- EntityModifier.parseExtras(mContext, accountType, insert, mIntentExtras);
+ if (oldState == null) {
+ // Parse any values from incoming intent
+ EntityModifier.parseExtras(mContext, newAccountType, insert, mIntentExtras);
+ } else {
+ EntityModifier.migrateStateForNewContact(mContext, oldState, insert,
+ oldAccountType, newAccountType);
+ }
// Ensure we have some default fields (if the account type does not support a field,
// ensureKind will not add it, so it is safe to add e.g. Event)
- EntityModifier.ensureKindExists(insert, accountType, Phone.CONTENT_ITEM_TYPE);
- EntityModifier.ensureKindExists(insert, accountType, Email.CONTENT_ITEM_TYPE);
- EntityModifier.ensureKindExists(insert, accountType, Note.CONTENT_ITEM_TYPE);
- EntityModifier.ensureKindExists(insert, accountType, Organization.CONTENT_ITEM_TYPE);
- EntityModifier.ensureKindExists(insert, accountType, Event.CONTENT_ITEM_TYPE);
- EntityModifier.ensureKindExists(insert, accountType, Website.CONTENT_ITEM_TYPE);
- EntityModifier.ensureKindExists(insert, accountType, StructuredPostal.CONTENT_ITEM_TYPE);
+ EntityModifier.ensureKindExists(insert, newAccountType, Phone.CONTENT_ITEM_TYPE);
+ EntityModifier.ensureKindExists(insert, newAccountType, Email.CONTENT_ITEM_TYPE);
+ EntityModifier.ensureKindExists(insert, newAccountType, Note.CONTENT_ITEM_TYPE);
+ EntityModifier.ensureKindExists(insert, newAccountType, Organization.CONTENT_ITEM_TYPE);
+ EntityModifier.ensureKindExists(insert, newAccountType, Event.CONTENT_ITEM_TYPE);
+ EntityModifier.ensureKindExists(insert, newAccountType, Website.CONTENT_ITEM_TYPE);
+ EntityModifier.ensureKindExists(insert, newAccountType, StructuredPostal.CONTENT_ITEM_TYPE);
if (mState == null) {
// Create state if none exists yet
@@ -519,6 +547,8 @@
mState.add(insert);
}
+ mRequestFocus = true;
+
bindEditors();
}
@@ -552,6 +582,13 @@
editor = (BaseRawContactEditorView)
inflater.inflate(R.layout.raw_contact_editor_view, mContent, false);
}
+ if (Intent.ACTION_INSERT.equals(mAction) && size == 1) {
+ final ArrayList<Account> accounts =
+ AccountTypeManager.getInstance(mContext).getAccounts(true);
+ if (accounts.size() > 1) {
+ addAccountSwitcher(mState.get(0), editor);
+ }
+ }
editor.setEnabled(mEnabled);
mContent.addView(editor);
@@ -562,19 +599,30 @@
new PhotoEditorListener(editor, type.readOnly));
if (editor instanceof RawContactEditorView) {
final RawContactEditorView rawContactEditor = (RawContactEditorView) editor;
- final TextFieldsEditorView nameEditor = rawContactEditor.getNameEditor();
- nameEditor.setEditorListener(new EditorListener() {
+ EditorListener listener = new EditorListener() {
@Override
public void onRequest(int request) {
- onContactNameChange(request, rawContactEditor, nameEditor);
+ if (request == EditorListener.FIELD_CHANGED) {
+ acquireAggregationSuggestions(rawContactEditor);
+ }
}
@Override
public void onDeleted(Editor removedEditor) {
}
- });
+ };
+ final TextFieldsEditorView nameEditor = rawContactEditor.getNameEditor();
+ if (mRequestFocus) {
+ nameEditor.requestFocus();
+ mRequestFocus = false;
+ }
+ nameEditor.setEditorListener(listener);
+
+ final TextFieldsEditorView phoneticNameEditor =
+ rawContactEditor.getPhoneticNameEditor();
+ phoneticNameEditor.setEditorListener(listener);
rawContactEditor.setAutoAddToDefaultGroup(mAutoAddToDefaultGroup);
if (rawContactId == mAggregationSuggestionsRawContactId) {
@@ -583,6 +631,8 @@
}
}
+ mRequestFocus = false;
+
bindGroupMetaData();
// Show editor now that we've loaded state
@@ -592,6 +642,7 @@
// Activity can be null if we have been detached from the Activity
final Activity activity = getActivity();
if (activity != null) activity.invalidateOptionsMenu();
+
}
private void bindGroupMetaData() {
@@ -606,6 +657,40 @@
}
}
+ private void addAccountSwitcher(
+ final EntityDelta currentState, BaseRawContactEditorView editor) {
+ ValuesDelta values = currentState.getValues();
+ final Account currentAccount = new Account(
+ values.getAsString(RawContacts.ACCOUNT_NAME),
+ values.getAsString(RawContacts.ACCOUNT_TYPE));
+ final View accountView = editor.findViewById(R.id.account);
+ final View anchorView = editor.findViewById(R.id.anchor_for_account_switcher);
+ accountView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ final ListPopupWindow popup = new ListPopupWindow(mContext, null);
+ final AccountsListAdapter adapter = new AccountsListAdapter(mContext, true);
+ popup.setWidth(anchorView.getWidth());
+ popup.setAnchorView(anchorView);
+ popup.setAdapter(adapter);
+ popup.setModal(true);
+ popup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
+ popup.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position,
+ long id) {
+ popup.dismiss();
+ Account newAccount = adapter.getItem(position);
+ if (!newAccount.equals(currentAccount)) {
+ rebindEditorsForNewContact(currentState, currentAccount, newAccount);
+ }
+ }
+ });
+ popup.show();
+ }
+ });
+ }
+
@Override
public void onCreateOptionsMenu(Menu menu, final MenuInflater inflater) {
inflater.inflate(R.menu.edit, menu);
@@ -671,14 +756,12 @@
// If we just started creating a new contact and haven't added any data, it's too
// early to do a join
- if (mState.size() == 1 && mState.get(0).isContactInsert()) {
- final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
- EntityModifier.trimEmpty(mState, accountTypes);
- if (mState.buildDiff().isEmpty()) {
- Toast.makeText(getActivity(), R.string.toast_join_with_empty_contact,
- Toast.LENGTH_LONG).show();
- return true;
- }
+ final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
+ if (mState.size() == 1 && mState.get(0).isContactInsert()
+ && !EntityModifier.hasChanges(mState, accountTypes)) {
+ Toast.makeText(getActivity(), R.string.toast_join_with_empty_contact,
+ Toast.LENGTH_LONG).show();
+ return true;
}
return save(SaveMode.JOIN);
@@ -739,7 +822,7 @@
// Launch gallery to crop the photo
final Intent intent = getCropImageIntent(Uri.fromFile(f));
- mSaveOnStop = false;
+ mStatus = Status.SUB_ACTIVITY;
startActivityForResult(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA);
} catch (Exception e) {
Log.e(TAG, "Cannot crop image", e);
@@ -767,29 +850,29 @@
* finishes the activity.
*/
public boolean save(int saveMode) {
- if (!hasValidState()) {
+ if (!hasValidState() || mStatus != Status.EDITING) {
return false;
}
// If we are about to close the editor - there is no need to refresh the data
- if (saveMode == SaveMode.CLOSE) {
+ if (saveMode == SaveMode.CLOSE || saveMode == SaveMode.SPLIT) {
getLoaderManager().destroyLoader(LOADER_DATA);
}
mStatus = Status.SAVING;
- // Trim any empty fields, and RawContacts, before persisting
final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
- EntityModifier.trimEmpty(mState, accountTypes);
-
- if (mState.buildDiff().isEmpty()) {
- onSaveCompleted(true, saveMode, mLookupUri);
+ if (!EntityModifier.hasChanges(mState, accountTypes)) {
+ onSaveCompleted(false, saveMode, mLookupUri);
return true;
}
- final PersistTask task = new PersistTask(this, saveMode);
- task.execute(mState);
+ setEnabled(false);
+ Intent intent = ContactSaveService.createSaveContactIntent(getActivity(), mState,
+ SAVE_MODE_EXTRA_KEY, saveMode, getActivity().getClass(),
+ ContactEditorActivity.ACTION_SAVE_COMPLETED);
+ getActivity().startService(intent);
return true;
}
@@ -822,7 +905,8 @@
}
private boolean revert() {
- if (mState == null || mState.buildDiff().isEmpty()) {
+ final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
+ if (mState == null || !EntityModifier.hasChanges(mState, accountTypes)) {
doRevertAction();
} else {
CancelEditDialogFragment.show(this);
@@ -837,11 +921,21 @@
}
public void onJoinCompleted(Uri uri) {
- onSaveCompleted(uri != null, SaveMode.RELOAD, uri);
+ onSaveCompleted(false, SaveMode.RELOAD, uri);
}
- public void onSaveCompleted(boolean success, int saveMode, Uri contactLookupUri) {
- Log.d(TAG, "onSaveCompleted(" + success + ", " + saveMode + ", " + contactLookupUri);
+ public void onSaveCompleted(boolean hadChanges, int saveMode, Uri contactLookupUri) {
+ boolean success = contactLookupUri != null;
+ Log.d(TAG, "onSaveCompleted(" + saveMode + ", " + contactLookupUri);
+ if (hadChanges) {
+ if (success) {
+ if (saveMode != SaveMode.JOIN) {
+ Toast.makeText(mContext, R.string.contactSavedToast, Toast.LENGTH_SHORT).show();
+ }
+ } else {
+ Toast.makeText(mContext, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
+ }
+ }
switch (saveMode) {
case SaveMode.CLOSE:
case SaveMode.HOME:
@@ -877,6 +971,7 @@
if (mListener != null) mListener.onSaveFinished(resultCode, resultIntent,
saveMode == SaveMode.HOME);
break;
+
case SaveMode.RELOAD:
case SaveMode.JOIN:
if (success && contactLookupUri != null) {
@@ -893,14 +988,14 @@
}
}
break;
+
case SaveMode.SPLIT:
- setEnabled(true);
+ mStatus = Status.CLOSING;
if (mListener != null) {
mListener.onContactSplit(contactLookupUri);
} else {
Log.d(TAG, "No listener registered, can not call onSplitFinished");
}
- mStatus = Status.EDITING;
break;
}
}
@@ -963,11 +1058,6 @@
void onContactSplit(Uri newLookupUri);
/**
- * User was presented with an account selection and couldn't decide.
- */
- void onAccountSelectorAborted();
-
- /**
* User has tapped Revert, close the fragment now.
*/
void onReverted();
@@ -1087,119 +1177,17 @@
* Returns the contact ID for the currently edited contact or 0 if the contact is new.
*/
protected long getContactId() {
- for (EntityDelta rawContact : mState) {
- Long contactId = rawContact.getValues().getAsLong(RawContacts.CONTACT_ID);
- if (contactId != null) {
- return contactId;
+ if (mState != null) {
+ for (EntityDelta rawContact : mState) {
+ Long contactId = rawContact.getValues().getAsLong(RawContacts.CONTACT_ID);
+ if (contactId != null) {
+ return contactId;
+ }
}
}
return 0;
}
-
- private void onContactNameChange(int request, final RawContactEditorView rawContactEditor,
- TextFieldsEditorView nameEditor) {
-
- switch (request) {
- case EditorListener.EDITOR_FORM_CHANGED:
- if (nameEditor.hasShortAndLongForms()) {
- if (nameEditor.areOptionalFieldsVisible()) {
- switchFromFullNameToStructuredName(nameEditor);
- } else {
- switchFromStructuredNameToFullName(nameEditor);
- }
- }
- break;
-
- case EditorListener.FIELD_CHANGED:
- if (nameEditor.hasShortAndLongForms()) {
- if (nameEditor.areOptionalFieldsVisible()) {
- eraseFullName(nameEditor.getValues());
- } else {
- eraseStructuredName(nameEditor.getValues());
- }
- }
- acquireAggregationSuggestions(rawContactEditor);
- break;
- }
- }
-
- private void switchFromFullNameToStructuredName(LabeledEditorView nameEditor) {
- ValuesDelta values = nameEditor.getValues();
-
- String displayName = values.getAsString(StructuredName.DISPLAY_NAME);
- if (displayName == null) {
- displayName = "";
- }
-
- Uri uri = ContactsContract.AUTHORITY_URI.buildUpon().appendPath("complete_name")
- .appendQueryParameter(StructuredName.DISPLAY_NAME, displayName).build();
- Cursor cursor = getActivity().getContentResolver().query(uri, new String[]{
- StructuredName.PREFIX,
- StructuredName.GIVEN_NAME,
- StructuredName.MIDDLE_NAME,
- StructuredName.FAMILY_NAME,
- StructuredName.SUFFIX,
- }, null, null, null);
-
- try {
- if (cursor.moveToFirst()) {
- eraseFullName(values);
- values.put(StructuredName.PREFIX, cursor.getString(0));
- values.put(StructuredName.GIVEN_NAME, cursor.getString(1));
- values.put(StructuredName.MIDDLE_NAME, cursor.getString(2));
- values.put(StructuredName.FAMILY_NAME, cursor.getString(3));
- values.put(StructuredName.SUFFIX, cursor.getString(4));
- }
- } finally {
- cursor.close();
- }
- }
-
- private void switchFromStructuredNameToFullName(LabeledEditorView nameEditor) {
- ValuesDelta values = nameEditor.getValues();
-
- Uri.Builder builder = ContactsContract.AUTHORITY_URI.buildUpon().appendPath(
- "complete_name");
- appendQueryParameter(builder, values, StructuredName.PREFIX);
- appendQueryParameter(builder, values, StructuredName.GIVEN_NAME);
- appendQueryParameter(builder, values, StructuredName.MIDDLE_NAME);
- appendQueryParameter(builder, values, StructuredName.FAMILY_NAME);
- appendQueryParameter(builder, values, StructuredName.SUFFIX);
- Uri uri = builder.build();
- Cursor cursor = getActivity().getContentResolver().query(uri, new String[]{
- StructuredName.DISPLAY_NAME,
- }, null, null, null);
-
- try {
- if (cursor.moveToFirst()) {
- eraseStructuredName(values);
- values.put(StructuredName.DISPLAY_NAME, cursor.getString(0));
- }
- } finally {
- cursor.close();
- }
- }
-
- private void eraseFullName(ValuesDelta values) {
- values.putNull(StructuredName.DISPLAY_NAME);
- }
-
- private void eraseStructuredName(ValuesDelta values) {
- values.putNull(StructuredName.PREFIX);
- values.putNull(StructuredName.GIVEN_NAME);
- values.putNull(StructuredName.MIDDLE_NAME);
- values.putNull(StructuredName.FAMILY_NAME);
- values.putNull(StructuredName.SUFFIX);
- }
-
- private void appendQueryParameter(Uri.Builder builder, ValuesDelta values, String field) {
- String value = values.getAsString(field);
- if (!TextUtils.isEmpty(value)) {
- builder.appendQueryParameter(field, value);
- }
- }
-
/**
* Triggers an asynchronous search for aggregation suggestions.
*/
@@ -1228,7 +1216,7 @@
@Override
public void onAggregationSuggestionChange() {
- if (!isAdded() || mState == null) {
+ if (!isAdded() || mState == null || mStatus != Status.EDITING) {
return;
}
@@ -1275,6 +1263,7 @@
}
adjustAggregationSuggestionViewLayout(rawContactView);
+ setAggregationSuggestionViewEnabled(mEnabled);
mAggregationSuggestionView.setVisibility(View.VISIBLE);
if (requestOnScreen) {
@@ -1351,6 +1340,10 @@
* contacts), save all changes, and stay in the editor.
*/
protected void doJoinSuggestedContact(long[] rawContactIds) {
+ if (!hasValidState() || mStatus != Status.EDITING) {
+ return;
+ }
+
mState.setJoinWithRawContacts(rawContactIds);
save(SaveMode.RELOAD);
}
@@ -1396,6 +1389,8 @@
*/
protected void doEditSuggestedContact(Uri contactUri) {
if (mListener != null) {
+ // make sure we don't save this contact when closing down
+ mStatus = Status.CLOSING;
mListener.onEditOtherContactRequested(
contactUri, mState.get(0).getContentValues());
}
@@ -1415,6 +1410,19 @@
mContent.requestRectangleOnScreen(rect);
}
+ public void setAggregationSuggestionViewEnabled(boolean enabled) {
+ if (mAggregationSuggestionView == null) {
+ return;
+ }
+
+ LinearLayout itemList = (LinearLayout) mAggregationSuggestionView.findViewById(
+ R.id.aggregation_suggestions);
+ int count = itemList.getChildCount();
+ for (int i = 0; i < count; i++) {
+ itemList.getChildAt(i).setEnabled(enabled);
+ }
+ }
+
/**
* Computes bounds of the supplied view relative to its ascendant.
*/
@@ -1430,133 +1438,6 @@
return rect;
}
- // TODO: There has to be a nicer way than this WeakAsyncTask...? Maybe call a service?
- /**
- * Background task for persisting edited contact data, using the changes
- * defined by a set of {@link EntityDelta}. This task starts
- * {@link EmptyService} to make sure the background thread can finish
- * persisting in cases where the system wants to reclaim our process.
- */
- public static class PersistTask extends
- WeakAsyncTask<EntityDeltaList, Void, Integer, ContactEditorFragment> {
- private static final int PERSIST_TRIES = 3;
-
- private static final int RESULT_UNCHANGED = 0;
- private static final int RESULT_SUCCESS = 1;
- private static final int RESULT_FAILURE = 2;
-
- private final Context mContext;
-
- private int mSaveMode;
- private Uri mContactLookupUri = null;
-
- public PersistTask(ContactEditorFragment target, int saveMode) {
- super(target);
- mSaveMode = saveMode;
- mContext = target.mContext;
- }
-
- /** {@inheritDoc} */
- @Override
- protected void onPreExecute(ContactEditorFragment target) {
- target.setEnabled(false);
-
- // Before starting this task, start an empty service to protect our
- // process from being reclaimed by the system.
- mContext.startService(new Intent(mContext, EmptyService.class));
- }
-
- /** {@inheritDoc} */
- @Override
- protected Integer doInBackground(ContactEditorFragment target, EntityDeltaList... params) {
- final ContentResolver resolver = mContext.getContentResolver();
-
- EntityDeltaList state = params[0];
-
- // Attempt to persist changes
- int tries = 0;
- Integer result = RESULT_FAILURE;
- while (tries++ < PERSIST_TRIES) {
- try {
- // Build operations and try applying
- final ArrayList<ContentProviderOperation> diff = state.buildDiff();
- ContentProviderResult[] results = null;
- if (!diff.isEmpty()) {
- results = resolver.applyBatch(ContactsContract.AUTHORITY, diff);
- }
-
- final long rawContactId = getRawContactId(state, diff, results);
- if (rawContactId != -1) {
- final Uri rawContactUri = ContentUris.withAppendedId(
- RawContacts.CONTENT_URI, rawContactId);
-
- // convert the raw contact URI to a contact URI
- mContactLookupUri = RawContacts.getContactLookupUri(resolver,
- rawContactUri);
- Log.d(TAG, "Looked up RawContact Uri " + rawContactUri +
- " into ContactLookupUri " + mContactLookupUri);
- } else {
- Log.w(TAG, "Could not determine RawContact ID after save");
- }
- result = (diff.size() > 0) ? RESULT_SUCCESS : RESULT_UNCHANGED;
- break;
-
- } catch (RemoteException e) {
- // Something went wrong, bail without success
- Log.e(TAG, "Problem persisting user edits", e);
- break;
-
- } catch (OperationApplicationException e) {
- // Version consistency failed, re-parent change and try again
- Log.w(TAG, "Version consistency failed, re-parenting: " + e.toString());
- final EntityDeltaList newState = EntityDeltaList.fromQuery(resolver,
- target.mQuerySelection, null, null);
- state = EntityDeltaList.mergeAfter(newState, state);
- }
- }
-
- return result;
- }
-
- private long getRawContactId(EntityDeltaList state,
- final ArrayList<ContentProviderOperation> diff,
- final ContentProviderResult[] results) {
- long rawContactId = state.findRawContactId();
- if (rawContactId != -1) {
- return rawContactId;
- }
-
-
- // we gotta do some searching for the id
- final int diffSize = diff.size();
- for (int i = 0; i < diffSize; i++) {
- ContentProviderOperation operation = diff.get(i);
- if (operation.getType() == ContentProviderOperation.TYPE_INSERT
- && operation.getUri().getEncodedPath().contains(
- RawContacts.CONTENT_URI.getEncodedPath())) {
- return ContentUris.parseId(results[i].uri);
- }
- }
- return -1;
- }
-
- /** {@inheritDoc} */
- @Override
- protected void onPostExecute(ContactEditorFragment target, Integer result) {
- Log.d(TAG, "onPostExecute(something," + result + "). mSaveMode=" + mSaveMode);
- if (result == RESULT_SUCCESS && mSaveMode != SaveMode.JOIN) {
- Toast.makeText(mContext, R.string.contactSavedToast, Toast.LENGTH_SHORT).show();
- } else if (result == RESULT_FAILURE) {
- Toast.makeText(mContext, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
- }
-
- // Stop the service that was protecting us
- mContext.stopService(new Intent(mContext, EmptyService.class));
-
- target.onSaveCompleted(result != RESULT_FAILURE, mSaveMode, mContactLookupUri);
- }
- }
-
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putParcelable(KEY_URI, mLookupUri);
@@ -1572,15 +1453,19 @@
if (mCurrentPhotoFile != null) {
outState.putString(KEY_CURRENT_PHOTO_FILE, mCurrentPhotoFile.toString());
}
- outState.putString(KEY_QUERY_SELECTION, mQuerySelection);
outState.putLong(KEY_CONTACT_ID_FOR_JOIN, mContactIdForJoin);
outState.putLong(KEY_SHOW_JOIN_SUGGESTIONS, mAggregationSuggestionsRawContactId);
outState.putBoolean(KEY_ENABLED, mEnabled);
+ outState.putInt(KEY_STATUS, mStatus);
super.onSaveInstanceState(outState);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (mStatus == Status.SUB_ACTIVITY) {
+ mStatus = Status.EDITING;
+ }
+
// Ignore failed requests
if (resultCode != Activity.RESULT_OK) return;
switch (requestCode) {
@@ -1726,24 +1611,6 @@
save(SaveMode.SPLIT);
}
- /**
- * Account was chosen in the selector. Create a RawContact for this account now
- */
- @Override
- public void onAccountChosen(Account account) {
- createContact(account);
- }
-
- /**
- * The account selector has been aborted. If we are in "New" mode, we have to close now
- */
- @Override
- public void onAccountSelectorCancelled() {
- if (!hasValidState() && mListener != null) {
- mListener.onAccountSelectorAborted();
- }
- }
-
private final class PhotoEditorListener
implements EditorListener, PhotoActionPopup.Listener {
private final BaseRawContactEditorView mEditor;
@@ -1825,7 +1692,7 @@
mCurrentPhotoFile = new File(PHOTO_DIR, getPhotoFileName());
final Intent intent = getTakePickIntent(mCurrentPhotoFile);
- mSaveOnStop = false;
+ mStatus = Status.SUB_ACTIVITY;
startActivityForResult(intent, REQUEST_CODE_CAMERA_WITH_DATA);
} catch (ActivityNotFoundException e) {
Toast.makeText(mContext, R.string.photoPickerNotFoundText,
@@ -1842,7 +1709,7 @@
try {
// Launch picker to choose photo for selected contact
final Intent intent = getPhotoPickIntent();
- mSaveOnStop = false;
+ mStatus = Status.SUB_ACTIVITY;
startActivityForResult(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA);
} catch (ActivityNotFoundException e) {
Toast.makeText(mContext, R.string.photoPickerNotFoundText,
diff --git a/src/com/android/contacts/editor/Editor.java b/src/com/android/contacts/editor/Editor.java
index d733e68..a70bf3f 100644
--- a/src/com/android/contacts/editor/Editor.java
+++ b/src/com/android/contacts/editor/Editor.java
@@ -16,8 +16,8 @@
package com.android.contacts.editor;
+import com.android.contacts.model.DataKind;
import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.AccountType.DataKind;
import com.android.contacts.model.EntityDelta.ValuesDelta;
import android.provider.ContactsContract.Data;
@@ -27,9 +27,7 @@
* {@link ValuesDelta} object.
*/
public interface Editor {
- /**
- * Listener for an {@link Editor}, usually to handle deleted items.
- */
+
public interface EditorListener {
/**
* Called when the given {@link Editor} has been deleted.
@@ -44,14 +42,21 @@
public static final int REQUEST_PICK_PHOTO = 1;
public static final int FIELD_CHANGED = 2;
+ public static final int FIELD_TURNED_EMPTY = 3;
+ public static final int FIELD_TURNED_NON_EMPTY = 4;
// The editor has switched between different representations of the same
// data, e.g. from full name to structured name
- public static final int EDITOR_FORM_CHANGED = 3;
+ public static final int EDITOR_FORM_CHANGED = 5;
}
/**
- * Prepare this editor for the given {@link ValuesDelta}, which
+ * Returns whether or not all the fields are empty in this {@link Editor}.
+ */
+ public boolean isEmpty();
+
+ /**
+ * Prepares this editor for the given {@link ValuesDelta}, which
* builds any needed views. Any changes performed by the user will be
* written back to that same object.
*/
diff --git a/src/com/android/contacts/editor/EventFieldEditorView.java b/src/com/android/contacts/editor/EventFieldEditorView.java
index 7345dbb..bf93d26 100644
--- a/src/com/android/contacts/editor/EventFieldEditorView.java
+++ b/src/com/android/contacts/editor/EventFieldEditorView.java
@@ -20,9 +20,9 @@
import com.android.contacts.datepicker.DatePicker;
import com.android.contacts.datepicker.DatePickerDialog;
import com.android.contacts.datepicker.DatePickerDialog.OnDateSetListener;
-import com.android.contacts.model.AccountType.DataKind;
import com.android.contacts.model.AccountType.EditField;
import com.android.contacts.model.AccountType.EventEditType;
+import com.android.contacts.model.DataKind;
import com.android.contacts.model.EntityDelta;
import com.android.contacts.model.EntityDelta.ValuesDelta;
import com.android.contacts.util.DateUtils;
@@ -32,14 +32,13 @@
import android.os.Bundle;
import android.text.TextUtils;
import android.util.AttributeSet;
-import android.view.Gravity;
import android.view.View;
import android.widget.Button;
-import android.widget.LinearLayout;
import java.text.ParsePosition;
import java.util.Calendar;
import java.util.Date;
+import java.util.Locale;
/**
* Editor that allows editing Events using a {@link DatePickerDialog}
@@ -48,7 +47,7 @@
/**
* Exchange requires 8:00 for birthdays
*/
- private final int DEFAULT_HOUR = 8;
+ private final static int DEFAULT_HOUR = 8;
private Button mDateView;
@@ -64,57 +63,30 @@
super(context, attrs, defStyle);
}
+ /** {@inheritDoc} */
@Override
- public int getBaseline(int row) {
- int baseline = super.getBaseline(row);
- if (mDateView != null) {
- // The date view will be centered vertically in the corresponding line item
- int lineItemHeight = getLineItemHeight(row);
- int offset = (lineItemHeight - mDateView.getMeasuredHeight()) / 2;
- baseline = Math.max(baseline, offset + mDateView.getBaseline());
- }
- return baseline;
- }
+ protected void onFinishInflate() {
+ super.onFinishInflate();
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
-
- int l1 = getPaddingLeft();
- int t1 = getPaddingTop();
- int r1 = getMeasuredWidth() - getPaddingRight();
-
- // Fields
- // Subtract buttons left and right if necessary
- final int labelWidth = (getLabel() != null) ? getLabel().getMeasuredWidth() : 0;
- final int deleteWidth = (getDelete() != null) ? getDelete().getMeasuredWidth() : 0;
- final int r2 = r1 - deleteWidth - labelWidth;
- if (mDateView != null) {
- int height = mDateView.getMeasuredHeight();
- int baseline = getBaseline(0);
- int top = t1 + baseline - mDateView.getBaseline();
- mDateView.layout(
- l1, top,
- r2, top + height);
- }
- }
-
- @Override
- protected int getLineItemHeight(int row) {
- int height = mDateView == null ? 0 : mDateView.getMeasuredHeight();
- return Math.max(height, super.getLineItemHeight(row));
+ mDateView = (Button) findViewById(R.id.date_view);
+ mDateView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showDialog(R.id.dialog_event_date_picker);
+ }
+ });
}
@Override
protected void requestFocusForFirstEditField() {
- if (mDateView != null) mDateView.requestFocus();
+ mDateView.requestFocus();
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
- if (mDateView != null) mDateView.setEnabled(!isReadOnly() && enabled);
+ mDateView.setEnabled(!isReadOnly() && enabled);
}
@Override
@@ -123,20 +95,7 @@
if (kind.fieldList.size() != 1) throw new IllegalStateException("kind must have 1 field");
super.setValues(kind, entry, state, readOnly, vig);
- if (mDateView == null) {
-
- mDateView = new Button(getContext(), null, android.R.attr.spinnerStyle);
- mDateView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
- LayoutParams.WRAP_CONTENT));
- mDateView.setEnabled(isEnabled() && !readOnly);
- mDateView.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- showDialog(R.id.dialog_event_date_picker);
- }
- });
- addView(mDateView);
- }
+ mDateView.setEnabled(isEnabled() && !readOnly);
rebuildDateView();
}
@@ -152,6 +111,11 @@
}
@Override
+ public boolean isEmpty() {
+ return TextUtils.isEmpty(mDateView.getText());
+ }
+
+ @Override
public Dialog createDialog(Bundle bundle) {
if (bundle == null) throw new IllegalArgumentException("bundle must not be null");
int dialogId = bundle.getInt(DIALOG_ID_KEY);
@@ -175,7 +139,7 @@
final String oldValue = getEntry().getAsString(column);
final DataKind kind = getKind();
- final Calendar calendar = Calendar.getInstance();
+ final Calendar calendar = Calendar.getInstance(DateUtils.UTC_TIMEZONE, Locale.US);
final int defaultYear = calendar.get(Calendar.YEAR);
// Check whether the year is optional
@@ -206,7 +170,7 @@
final String oldValue = getEntry().getAsString(column);
final DataKind kind = getKind();
- final Calendar calendar = Calendar.getInstance();
+ final Calendar calendar = Calendar.getInstance(DateUtils.UTC_TIMEZONE, Locale.US);
final int defaultYear = calendar.get(Calendar.YEAR);
// Check whether the year is optional
@@ -245,7 +209,8 @@
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
if (year == 0 && !isYearOptional) throw new IllegalStateException();
- final Calendar outCalendar = Calendar.getInstance();
+ final Calendar outCalendar =
+ Calendar.getInstance(DateUtils.UTC_TIMEZONE, Locale.US);
// If no year specified, set it to 1900. The format string will ignore that year
// For formats other than Exchange, the time of the day is ignored
@@ -267,4 +232,11 @@
oldYear, oldMonth, oldDay, isYearOptional);
return resultDialog;
}
+
+ /**
+ * @return Default hour which should be used for birthday field.
+ */
+ public static int getDefaultHourForBirthday() {
+ return DEFAULT_HOUR;
+ }
}
diff --git a/src/com/android/contacts/editor/ExternalRawContactEditorView.java b/src/com/android/contacts/editor/ExternalRawContactEditorView.java
index aaa1e44..89cace0 100644
--- a/src/com/android/contacts/editor/ExternalRawContactEditorView.java
+++ b/src/com/android/contacts/editor/ExternalRawContactEditorView.java
@@ -20,7 +20,7 @@
import com.android.contacts.R;
import com.android.contacts.editor.ExternalRawContactEditorView.Listener;
import com.android.contacts.model.AccountType;
-import com.android.contacts.model.AccountType.DataKind;
+import com.android.contacts.model.DataKind;
import com.android.contacts.model.EntityDelta;
import com.android.contacts.model.EntityDelta.ValuesDelta;
import com.android.contacts.model.EntityModifier;
@@ -60,9 +60,9 @@
private Button mEditExternallyButton;
private ViewGroup mGeneral;
- private ImageView mHeaderIcon;
- private TextView mHeaderAccountType;
- private TextView mHeaderAccountName;
+ private ImageView mAccountIcon;
+ private TextView mAccountTypeTextView;
+ private TextView mAccountNameTextView;
private String mAccountName;
private String mAccountType;
@@ -102,9 +102,9 @@
mEditExternallyButton.setOnClickListener(this);
mGeneral = (ViewGroup)findViewById(R.id.sect_general);
- mHeaderIcon = (ImageView) findViewById(R.id.header_icon);
- mHeaderAccountType = (TextView) findViewById(R.id.header_account_type);
- mHeaderAccountName = (TextView) findViewById(R.id.header_account_name);
+ mAccountIcon = (ImageView) findViewById(R.id.account_icon);
+ mAccountTypeTextView = (TextView) findViewById(R.id.account_type);
+ mAccountNameTextView = (TextView) findViewById(R.id.account_name);
}
/**
@@ -132,11 +132,11 @@
accountType = mContext.getString(R.string.account_phone);
}
if (!TextUtils.isEmpty(mAccountName)) {
- mHeaderAccountName.setText(
+ mAccountNameTextView.setText(
mContext.getString(R.string.from_account_format, mAccountName));
}
- mHeaderAccountType.setText(mContext.getString(R.string.account_type_format, accountType));
- mHeaderIcon.setImageDrawable(type.getDisplayIcon(mContext));
+ mAccountTypeTextView.setText(mContext.getString(R.string.account_type_format, accountType));
+ mAccountIcon.setImageDrawable(type.getDisplayIcon(mContext));
mRawContactId = values.getAsLong(RawContacts._ID);
diff --git a/src/com/android/contacts/editor/GroupMembershipView.java b/src/com/android/contacts/editor/GroupMembershipView.java
index 8845aa3..d242a1b 100644
--- a/src/com/android/contacts/editor/GroupMembershipView.java
+++ b/src/com/android/contacts/editor/GroupMembershipView.java
@@ -19,7 +19,7 @@
import com.android.contacts.GroupMetaDataLoader;
import com.android.contacts.R;
import com.android.contacts.interactions.GroupCreationDialogFragment;
-import com.android.contacts.model.AccountType.DataKind;
+import com.android.contacts.model.DataKind;
import com.android.contacts.model.EntityDelta;
import com.android.contacts.model.EntityDelta.ValuesDelta;
import com.android.contacts.model.EntityModifier;
diff --git a/src/com/android/contacts/editor/KindSectionView.java b/src/com/android/contacts/editor/KindSectionView.java
index 4ce8dda..b472279 100644
--- a/src/com/android/contacts/editor/KindSectionView.java
+++ b/src/com/android/contacts/editor/KindSectionView.java
@@ -18,23 +18,22 @@
import com.android.contacts.R;
import com.android.contacts.editor.Editor.EditorListener;
-import com.android.contacts.model.AccountType.DataKind;
+import com.android.contacts.model.DataKind;
import com.android.contacts.model.EntityDelta;
import com.android.contacts.model.EntityDelta.ValuesDelta;
import com.android.contacts.model.EntityModifier;
import android.content.Context;
-import android.os.Handler;
-import android.provider.ContactsContract.Data;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
+import java.util.List;
/**
* Custom view for an entire section of data as segmented by
@@ -45,9 +44,8 @@
private static final String TAG = "KindSectionView";
private ViewGroup mEditors;
- private View mAddPlusButtonContainer;
- private ImageButton mAddPlusButton;
- private TextView mTitle;
+ private View mAddFieldFooter;
+ private TextView mAddFieldText;
private String mTitleString;
private DataKind mKind;
@@ -56,7 +54,7 @@
private ViewIdGenerator mViewIdGenerator;
- private int mMinLineItemHeight;
+ private LayoutInflater mInflater;
public KindSectionView(Context context) {
this(context, null);
@@ -64,8 +62,6 @@
public KindSectionView(Context context, AttributeSet attrs) {
super(context, attrs);
- mMinLineItemHeight = context.getResources().getDimensionPixelSize(
- R.dimen.editor_min_line_item_height);
}
@Override
@@ -78,26 +74,13 @@
}
}
- if (mAddPlusButton != null) {
- mAddPlusButton.setEnabled(enabled && !mReadOnly);
+ if (enabled && !mReadOnly) {
+ mAddFieldFooter.setVisibility(View.VISIBLE);
+ } else {
+ mAddFieldFooter.setVisibility(View.GONE);
}
}
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
-
- if (mAddPlusButton == null || mEditors == null || mEditors.getChildCount() < 2) {
- return;
- }
-
- // Align the "+" button with the "-" button in the last editor
- View lastEditor = mEditors.getChildAt(mEditors.getChildCount() - 1);
- int top = lastEditor.getTop();
- mAddPlusButtonContainer.layout(mAddPlusButtonContainer.getLeft(), top,
- mAddPlusButtonContainer.getRight(), top + mAddPlusButtonContainer.getHeight());
- }
-
public boolean isReadOnly() {
return mReadOnly;
}
@@ -108,37 +91,36 @@
setDrawingCacheEnabled(true);
setAlwaysDrawnWithCacheEnabled(true);
- mEditors = (ViewGroup)findViewById(R.id.kind_editors);
+ mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mAddPlusButtonContainer = findViewById(R.id.kind_plus_container);
- mAddPlusButton = (ImageButton) findViewById(R.id.kind_plus);
- mAddPlusButton.setOnClickListener(new OnClickListener() {
+ mEditors = (ViewGroup)findViewById(R.id.kind_editors);
+ mAddFieldText = (TextView) findViewById(R.id.add_text);
+ mAddFieldFooter = findViewById(R.id.add_field_footer);
+ mAddFieldFooter.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- // defer action so that the pressed state of the button is visible shortly
- new Handler().post(new Runnable() {
- @Override
- public void run() {
- addItem();
- }
- });
+ // Setup click listener to add an empty field when the footer is clicked.
+ mAddFieldFooter.setVisibility(View.GONE);
+ addItem();
}
});
-
- mTitle = (TextView)findViewById(R.id.kind_title);
}
/** {@inheritDoc} */
@Override
public void onDeleted(Editor editor) {
- updateAddVisible();
- updateVisible();
+ updateAddFooterVisible();
+ updateSectionVisible();
}
/** {@inheritDoc} */
@Override
public void onRequest(int request) {
- // Ignore requests
+ // If a field has become empty or non-empty, then check if another row
+ // can be added dynamically.
+ if (request == FIELD_TURNED_EMPTY || request == FIELD_TURNED_NON_EMPTY) {
+ updateAddFooterVisible();
+ }
}
public void setState(DataKind kind, EntityDelta state, boolean readOnly, ViewIdGenerator vig) {
@@ -153,11 +135,17 @@
mTitleString = (kind.titleRes == -1 || kind.titleRes == 0)
? ""
: getResources().getString(kind.titleRes);
- mTitle.setText(mTitleString);
+
+ // Set "add field" footer message according to MIME type. Some MIME types
+ // can only have max 1 field, so the resource ID will be -1 if these sections
+ // should not have an "Add field" option.
+ if (kind.addNewFieldTextResourceId != -1) {
+ mAddFieldText.setText(getResources().getString(kind.addNewFieldTextResourceId));
+ }
rebuildFromState();
- updateAddVisible();
- updateVisible();
+ updateAddFooterVisible();
+ updateSectionVisible();
}
public String getTitle() {
@@ -193,16 +181,13 @@
*/
private View createEditorView(ValuesDelta entry) {
final View view;
- if (mKind.editorClass == null) {
- view = new TextFieldsEditorView(mContext);
- } else {
- try {
- view = mKind.editorClass.getConstructor(Context.class).newInstance(
- mContext);
- } catch (Exception e) {
- throw new RuntimeException(
- "Cannot allocate editor for " + mKind.editorClass);
- }
+ try {
+ view = mInflater.inflate(mKind.editorLayoutResourceId, mEditors, false);
+ } catch (Exception e) {
+ throw new RuntimeException(
+ "Cannot allocate editor with layout resource ID " +
+ mKind.editorLayoutResourceId + " for MIME type " + mKind.mimeType +
+ " with error " + e.toString());
}
view.setEnabled(isEnabled());
@@ -231,26 +216,68 @@
return true;
}
- private void updateVisible() {
+ private void updateSectionVisible() {
setVisibility(getEditorCount() != 0 ? VISIBLE : GONE);
}
-
- protected void updateAddVisible() {
- final boolean isVisible;
- if (!mKind.isList) {
- isVisible = false;
- } else {
- // Set enabled state on the "add" view
- final boolean canInsert = EntityModifier.canInsert(mState, mKind);
- isVisible = !mReadOnly && canInsert;
+ protected void updateAddFooterVisible() {
+ if (!mReadOnly && mKind.isList) {
+ // First determine whether there are any existing empty editors.
+ updateEmptyEditors();
+ // If there are no existing empty editors and it's possible to add
+ // another field, then make the "add footer" field visible.
+ if (!hasEmptyEditor() && EntityModifier.canInsert(mState, mKind)) {
+ mAddFieldFooter.setVisibility(View.VISIBLE);
+ return;
+ }
}
- mAddPlusButton.setVisibility(isVisible ? View.VISIBLE : View.INVISIBLE);
+ mAddFieldFooter.setVisibility(View.GONE);
+ }
+
+ /**
+ * Updates the editors being displayed to the user removing extra empty
+ * {@link Editor}s, so there is only max 1 empty {@link Editor} view at a time.
+ */
+ private void updateEmptyEditors() {
+ List<View> emptyEditors = getEmptyEditors();
+
+ // If there is more than 1 empty editor, then remove it from the list of editors.
+ if (emptyEditors.size() > 1) {
+ for (View emptyEditorView : emptyEditors) {
+ // If no child {@link View}s are being focused on within
+ // this {@link View}, then remove this empty editor.
+ if (emptyEditorView.findFocus() == null) {
+ mEditors.removeView(emptyEditorView);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns a list of empty editor views in this section.
+ */
+ private List<View> getEmptyEditors() {
+ List<View> emptyEditorViews = new ArrayList<View>();
+ for (int i = 0; i < mEditors.getChildCount(); i++) {
+ View view = mEditors.getChildAt(i);
+ if (((Editor) view).isEmpty()) {
+ emptyEditorViews.add(view);
+ }
+ }
+ return emptyEditorViews;
+ }
+
+ /**
+ * Returns true if one of the editors has all of its fields empty, or false
+ * otherwise.
+ */
+ private boolean hasEmptyEditor() {
+ return getEmptyEditors().size() > 0;
}
public void addItem() {
ValuesDelta values = null;
- // if this is a list, we can freely add. if not, only allow adding the first
+ // If this is a list, we can freely add. If not, only allow adding the first.
if (!mKind.isList) {
if (getEditorCount() == 1) {
return;
@@ -269,14 +296,19 @@
}
final View newField = createEditorView(values);
- newField.requestFocus();
+ post(new Runnable() {
- // For non-lists (e.g. Notes we can only have one field. in that case we need to disable
- // the add button
- updateAddVisible();
+ @Override
+ public void run() {
+ newField.requestFocus();
+ }
+ });
+
+ // Hide the "add field" footer because there is now a blank field.
+ mAddFieldFooter.setVisibility(View.GONE);
// Ensure we are visible
- updateVisible();
+ updateSectionVisible();
}
public int getEditorCount() {
diff --git a/src/com/android/contacts/editor/LabeledEditorView.java b/src/com/android/contacts/editor/LabeledEditorView.java
index 971a023..af5ae65 100644
--- a/src/com/android/contacts/editor/LabeledEditorView.java
+++ b/src/com/android/contacts/editor/LabeledEditorView.java
@@ -18,23 +18,22 @@
import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType.DataKind;
import com.android.contacts.model.AccountType.EditType;
+import com.android.contacts.model.DataKind;
import com.android.contacts.model.EntityDelta;
import com.android.contacts.model.EntityDelta.ValuesDelta;
import com.android.contacts.model.EntityModifier;
import com.android.contacts.util.DialogManager;
import com.android.contacts.util.DialogManager.DialogShowingView;
-import com.android.contacts.util.ThemeUtils;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Entity;
-import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@@ -44,32 +43,36 @@
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.EditText;
-import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import java.util.List;
/**
- * Base class for editors that handles labels and values.
- * Uses {@link ValuesDelta} to read any existing
- * {@link Entity} values, and to correctly write any changes values.
+ * Base class for editors that handles labels and values. Uses
+ * {@link ValuesDelta} to read any existing {@link Entity} values, and to
+ * correctly write any changes values.
*/
-public abstract class LabeledEditorView extends ViewGroup implements Editor, DialogShowingView {
+public abstract class LabeledEditorView extends LinearLayout implements Editor, DialogShowingView {
protected static final String DIALOG_ID_KEY = "dialog_id";
private static final int DIALOG_ID_CUSTOM = 1;
private static final int INPUT_TYPE_CUSTOM = EditorInfo.TYPE_CLASS_TEXT
| EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS;
+ private TextView mTitle;
private Spinner mLabel;
private EditTypeAdapter mEditTypeAdapter;
- private ImageButton mDelete;
+ private View mDeleteContainer;
+ private ImageView mDelete;
private DataKind mKind;
private ValuesDelta mEntry;
private EntityDelta mState;
private boolean mReadOnly;
+ private boolean mWasEmpty = true;
private EditType mType;
@@ -116,6 +119,39 @@
R.dimen.editor_min_line_item_height);
}
+ /** {@inheritDoc} */
+ @Override
+ protected void onFinishInflate() {
+
+ mTitle = (TextView) findViewById(R.id.title);
+
+ mLabel = (Spinner) findViewById(R.id.spinner);
+ mLabel.setOnItemSelectedListener(mSpinnerListener);
+
+ mDelete = (ImageView) findViewById(R.id.delete_button);
+ mDeleteContainer = findViewById(R.id.delete_button_container);
+ mDeleteContainer.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // defer removal of this button so that the pressed state is visible shortly
+ new Handler().post(new Runnable() {
+ @Override
+ public void run() {
+ // Keep around in model, but mark as deleted
+ mEntry.markDeleted();
+
+ ((ViewGroup) getParent()).removeView(LabeledEditorView.this);
+
+ if (mListener != null) {
+ // Notify listener when present
+ mListener.onDeleted(LabeledEditorView.this);
+ }
+ }
+ });
+ }
+ });
+ }
+
public boolean isReadOnly() {
return mReadOnly;
}
@@ -128,96 +164,21 @@
}
/**
- * Returns the number of rows in this editor, including the invisible ones.
- */
- protected int getLineItemCount() {
- return 1;
- }
-
- protected boolean isLineItemVisible(int row) {
- return true;
- }
-
- protected int getLineItemHeight(int row) {
- int fieldHeight = 0;
- int buttonHeight = 0;
- if (row == 0) {
- // summarize the EditText heights
- if (mLabel != null) {
- fieldHeight = mLabel.getMeasuredHeight();
- }
-
- // Ensure there is enough space for the minus button
- View deleteButton = getDelete();
- final int deleteHeight = (deleteButton != null) ? deleteButton.getMeasuredHeight() : 0;
- buttonHeight += deleteHeight;
- }
-
- return Math.max(Math.max(buttonHeight, fieldHeight), mMinLineItemHeight);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- measureChildren(widthMeasureSpec, heightMeasureSpec);
-
- int height = 0;
- height += getPaddingTop() + getPaddingBottom();
-
- int count = getLineItemCount();
- for (int i = 0; i < count; i++) {
- if (isLineItemVisible(i)) {
- height += getLineItemHeight(i);
- }
- }
-
- setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
- resolveSize(height, heightMeasureSpec));
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- // Subtract padding from the borders ==> x1 variables
- int t1 = getPaddingTop();
- int r1 = getMeasuredWidth() - getPaddingRight();
- int b1 = getMeasuredHeight() - getPaddingBottom();
-
- final int r2;
- if (mDelete != null) {
- r2 = r1 - mDelete.getMeasuredWidth();
- // Vertically center the delete button in the first line item
- int height = mDelete.getMeasuredHeight();
- int top = t1 + (mMinLineItemHeight - height) / 2;
- mDelete.layout(
- r2, top,
- r1, top + height);
- } else {
- r2 = r1;
- }
-
- if (mLabel != null) {
- int baseline = getBaseline(0);
- int y = t1 + baseline - mLabel.getBaseline();
- mLabel.layout(
- r2 - mLabel.getMeasuredWidth(), y,
- r2, y + mLabel.getMeasuredHeight());
- }
- }
-
- /**
* Creates or removes the type/label button. Doesn't do anything if already correctly configured
*/
private void setupLabelButton(boolean shouldExist) {
- if (shouldExist && mLabel == null) {
- mLabel = new Spinner(mContext);
- final int width =
- mContext.getResources().getDimensionPixelSize(R.dimen.editor_type_label_width);
- mLabel.setLayoutParams(new LayoutParams(width, LayoutParams.WRAP_CONTENT));
- mLabel.setOnItemSelectedListener(mSpinnerListener);
+ if (mTitle == null) {
+ return;
+ }
+ if (shouldExist) {
mLabel.setEnabled(!mReadOnly && isEnabled());
- addView(mLabel);
- } else if (!shouldExist && mLabel != null) {
- removeView(mLabel);
- mLabel = null;
+ mLabel.setVisibility(View.VISIBLE);
+
+ // Since there's a spinner for this editor, use this as the title
+ // instead of the title TextView.
+ mTitle.setVisibility(View.GONE);
+ } else {
+ mLabel.setVisibility(View.GONE);
}
}
@@ -225,46 +186,11 @@
* Creates or removes the remove button. Doesn't do anything if already correctly configured
*/
private void setupDeleteButton(boolean shouldExist) {
- if (shouldExist && mDelete == null) {
- mDelete = new ImageButton(mContext);
- mDelete.setImageResource(R.drawable.ic_menu_remove_field_holo_light);
- mDelete.setBackgroundResource(
- ThemeUtils.getSelectableItemBackground(mContext.getTheme()));
- final Resources resources = mContext.getResources();
- mDelete.setPadding(
- resources.getDimensionPixelOffset(R.dimen.editor_round_button_padding_left),
- resources.getDimensionPixelOffset(R.dimen.editor_round_button_padding_top),
- resources.getDimensionPixelOffset(R.dimen.editor_round_button_padding_right),
- resources.getDimensionPixelOffset(R.dimen.editor_round_button_padding_bottom));
- mDelete.setContentDescription(
- getResources().getText(R.string.description_minus_button));
- mDelete.setLayoutParams(
- new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
- mDelete.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- // defer removal of this button so that the pressed state is visible shortly
- new Handler().post(new Runnable() {
- @Override
- public void run() {
- // Keep around in model, but mark as deleted
- mEntry.markDeleted();
-
- ((ViewGroup) getParent()).removeView(LabeledEditorView.this);
-
- if (mListener != null) {
- // Notify listener when present
- mListener.onDeleted(LabeledEditorView.this);
- }
- }
- });
- }
- });
+ if (shouldExist) {
+ mDeleteContainer.setVisibility(View.VISIBLE);
mDelete.setEnabled(!mReadOnly && isEnabled());
- addView(mDelete);
- } else if (!shouldExist && mDelete != null) {
- removeView(mDelete);
- mDelete = null;
+ } else {
+ mDeleteContainer.setVisibility(View.GONE);
}
}
@@ -287,15 +213,15 @@
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
- if (mLabel != null) mLabel.setEnabled(!mReadOnly && enabled);
- if (mDelete != null) mDelete.setEnabled(!mReadOnly && enabled);
+ mLabel.setEnabled(!mReadOnly && enabled);
+ mDelete.setEnabled(!mReadOnly && enabled);
}
public Spinner getLabel() {
return mLabel;
}
- public ImageButton getDelete() {
+ public ImageView getDelete() {
return mDelete;
}
@@ -316,7 +242,6 @@
* possible custom label string.
*/
private void rebuildLabel() {
- if (mLabel == null) return;
mEditTypeAdapter = new EditTypeAdapter(mContext);
mLabel.setAdapter(mEditTypeAdapter);
if (mEditTypeAdapter.hasCustomSelection()) {
@@ -326,11 +251,9 @@
}
}
- /** {@inheritDoc} */
@Override
public void onFieldChanged(String column, String value) {
- String oldValue = mEntry.getAsString(column);
- if (oldValue == null && value.equals("") || oldValue != null && oldValue.equals(value)) {
+ if (!isFieldChanged(column, value)) {
return;
}
@@ -339,6 +262,25 @@
if (mListener != null) {
mListener.onRequest(EditorListener.FIELD_CHANGED);
}
+
+ boolean isEmpty = isEmpty();
+ if (mWasEmpty != isEmpty) {
+ if (isEmpty) {
+ mListener.onRequest(EditorListener.FIELD_TURNED_EMPTY);
+ } else {
+ mListener.onRequest(EditorListener.FIELD_TURNED_NON_EMPTY);
+ }
+ mWasEmpty = isEmpty;
+ }
+ }
+
+ protected boolean isFieldChanged(String column, String value) {
+ final String dbValue = mEntry.getAsString(column);
+ // nullable fields (e.g. Middle Name) are usually represented as empty columns,
+ // so lets treat null and empty space equivalently here
+ final String dbValueNoNull = dbValue == null ? "" : dbValue;
+ final String valueNoNull = value == null ? "" : value;
+ return !TextUtils.equals(dbValueNoNull, valueNoNull);
}
protected void rebuildValues() {
@@ -366,10 +308,22 @@
}
setVisibility(View.VISIBLE);
+ // TODO: handle resources from remote packages
+ String titleString = (kind.titleRes == -1 || kind.titleRes == 0)
+ ? ""
+ : getResources().getString(kind.titleRes);
+
+ // If there is a title field, then setup the title (although it may not be shown if there is
+ // a Spinner setup later). There are cases where a title may not be present (i.e. structured
+ // name).
+ if (mTitle != null) {
+ mTitle.setText(titleString.toUpperCase());
+ }
+
// Display label selector if multiple types available
final boolean hasTypes = EntityModifier.hasEditTypes(kind);
setupLabelButton(hasTypes);
- if (mLabel != null) mLabel.setEnabled(!readOnly && isEnabled());
+ mLabel.setEnabled(!readOnly && isEnabled());
if (hasTypes) {
mType = EntityModifier.getCurrentType(entry, kind);
rebuildLabel();
@@ -548,7 +502,7 @@
} else {
text = getContext().getString(type.labelRes);
}
- textView.setText(text);
+ textView.setText(text.toUpperCase());
return view;
}
}
diff --git a/src/com/android/contacts/editor/PhoneticNameEditorView.java b/src/com/android/contacts/editor/PhoneticNameEditorView.java
new file mode 100644
index 0000000..cfc9b13
--- /dev/null
+++ b/src/com/android/contacts/editor/PhoneticNameEditorView.java
@@ -0,0 +1,189 @@
+/*
+ * 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.editor;
+
+import com.android.contacts.model.DataKind;
+import com.android.contacts.model.EntityDelta;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+
+/**
+ * A dedicated editor for phonetic name. It is similar to {@link StructuredNameEditorView}.
+ */
+public class PhoneticNameEditorView extends TextFieldsEditorView {
+
+ private static class PhoneticValuesDelta extends ValuesDelta {
+ private ValuesDelta mValues;
+ private String mPhoneticName;
+
+ public PhoneticValuesDelta(ValuesDelta values) {
+ mValues = values;
+ buildPhoneticName();
+ }
+
+ @Override
+ public void put(String key, String value) {
+ if (key.equals(DataKind.PSEUDO_COLUMN_PHONETIC_NAME)) {
+ mPhoneticName = value;
+ parsePhoneticName(value);
+ } else {
+ mValues.put(key, value);
+ buildPhoneticName();
+ }
+ }
+
+ @Override
+ public String getAsString(String key) {
+ if (key.equals(DataKind.PSEUDO_COLUMN_PHONETIC_NAME)) {
+ return mPhoneticName;
+ } else {
+ return mValues.getAsString(key);
+ }
+ }
+
+ private void parsePhoneticName(String value) {
+ ContentValues values = PhoneticNameEditorView.parsePhoneticName(value, null);
+ mValues.put(StructuredName.PHONETIC_FAMILY_NAME,
+ values.getAsString(StructuredName.PHONETIC_FAMILY_NAME));
+ mValues.put(StructuredName.PHONETIC_MIDDLE_NAME,
+ values.getAsString(StructuredName.PHONETIC_MIDDLE_NAME));
+ mValues.put(StructuredName.PHONETIC_GIVEN_NAME,
+ values.getAsString(StructuredName.PHONETIC_GIVEN_NAME));
+ }
+
+ private void buildPhoneticName() {
+ String family = mValues.getAsString(StructuredName.PHONETIC_FAMILY_NAME);
+ String middle = mValues.getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
+ String given = mValues.getAsString(StructuredName.PHONETIC_GIVEN_NAME);
+ mPhoneticName = PhoneticNameEditorView.buildPhoneticName(family, middle, given);
+ }
+
+ @Override
+ public Long getId() {
+ return mValues.getId();
+ }
+
+ @Override
+ public boolean isVisible() {
+ return mValues.isVisible();
+ }
+ }
+
+ /**
+ * 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 ContentValues parsePhoneticName(String phoneticName, ContentValues values) {
+ 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 (values == null) {
+ values = new ContentValues();
+ }
+ values.put(StructuredName.PHONETIC_FAMILY_NAME, family);
+ values.put(StructuredName.PHONETIC_MIDDLE_NAME, middle);
+ values.put(StructuredName.PHONETIC_GIVEN_NAME, given);
+ return values;
+ }
+
+ /**
+ * 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;
+ }
+ }
+
+ public PhoneticNameEditorView(Context context) {
+ super(context);
+ }
+
+ public PhoneticNameEditorView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public PhoneticNameEditorView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public void setValues(DataKind kind, ValuesDelta entry, EntityDelta state, boolean readOnly,
+ ViewIdGenerator vig) {
+ if (!(entry instanceof PhoneticValuesDelta)) {
+ entry = new PhoneticValuesDelta(entry);
+ }
+ super.setValues(kind, entry, state, readOnly, vig);
+ }
+
+ public boolean hasData() {
+ ValuesDelta entry = getEntry();
+
+ String family = entry.getAsString(StructuredName.PHONETIC_FAMILY_NAME);
+ String middle = entry.getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
+ String given = entry.getAsString(StructuredName.PHONETIC_GIVEN_NAME);
+
+ return !TextUtils.isEmpty(family) || !TextUtils.isEmpty(middle)
+ || !TextUtils.isEmpty(given);
+ }
+}
diff --git a/src/com/android/contacts/editor/PhotoActionPopup.java b/src/com/android/contacts/editor/PhotoActionPopup.java
index ae76afe..bc50da9 100644
--- a/src/com/android/contacts/editor/PhotoActionPopup.java
+++ b/src/com/android/contacts/editor/PhotoActionPopup.java
@@ -101,6 +101,7 @@
listPopupWindow.setWidth(context.getResources().getDimensionPixelSize(
R.dimen.photo_action_popup_width));
listPopupWindow.setModal(true);
+ listPopupWindow.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
return listPopupWindow;
}
diff --git a/src/com/android/contacts/editor/PhotoEditorView.java b/src/com/android/contacts/editor/PhotoEditorView.java
index 89633fd..7b86291 100644
--- a/src/com/android/contacts/editor/PhotoEditorView.java
+++ b/src/com/android/contacts/editor/PhotoEditorView.java
@@ -17,8 +17,8 @@
package com.android.contacts.editor;
import com.android.contacts.R;
+import com.android.contacts.model.DataKind;
import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.AccountType.DataKind;
import com.android.contacts.model.EntityDelta.ValuesDelta;
import android.content.Context;
@@ -178,4 +178,9 @@
public void setDeletable(boolean deletable) {
// Photo is not deletable
}
+
+ @Override
+ public boolean isEmpty() {
+ return !mHasSetPhoto;
+ }
}
diff --git a/src/com/android/contacts/editor/RawContactEditorView.java b/src/com/android/contacts/editor/RawContactEditorView.java
index 496144b..5ef2c21 100644
--- a/src/com/android/contacts/editor/RawContactEditorView.java
+++ b/src/com/android/contacts/editor/RawContactEditorView.java
@@ -19,12 +19,14 @@
import com.android.contacts.GroupMetaDataLoader;
import com.android.contacts.R;
import com.android.contacts.model.AccountType;
-import com.android.contacts.model.AccountType.DataKind;
import com.android.contacts.model.AccountType.EditType;
+import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.DataKind;
import com.android.contacts.model.EntityDelta;
import com.android.contacts.model.EntityDelta.ValuesDelta;
import com.android.contacts.model.EntityModifier;
+import android.accounts.Account;
import android.content.Context;
import android.content.Entity;
import android.database.Cursor;
@@ -62,14 +64,16 @@
public class RawContactEditorView extends BaseRawContactEditorView {
private LayoutInflater mInflater;
- private TextFieldsEditorView mName;
+ private StructuredNameEditorView mName;
+ private PhoneticNameEditorView mPhoneticName;
private GroupMembershipView mGroupMembershipView;
private ViewGroup mFields;
- private ImageView mHeaderIcon;
- private TextView mHeaderAccountType;
- private TextView mHeaderAccountName;
+ private View mAccountContainer;
+ private ImageView mAccountIcon;
+ private TextView mAccountTypeTextView;
+ private TextView mAccountNameTextView;
private Button mAddFieldButton;
@@ -79,6 +83,8 @@
private DataKind mGroupMembershipKind;
private EntityDelta mState;
+ private boolean mPhoneticNameAdded;
+
public RawContactEditorView(Context context) {
super(context);
}
@@ -93,11 +99,15 @@
View view = getPhotoEditor();
if (view != null) {
- view.setEnabled(isEnabled());
+ view.setEnabled(enabled);
}
if (mName != null) {
- mName.setEnabled(isEnabled());
+ mName.setEnabled(enabled);
+ }
+
+ if (mPhoneticName != null) {
+ mPhoneticName.setEnabled(enabled);
}
if (mFields != null) {
@@ -111,7 +121,7 @@
mGroupMembershipView.setEnabled(enabled);
}
- mAddFieldButton.setEnabled(isEnabled());
+ mAddFieldButton.setEnabled(enabled);
}
@Override
@@ -122,15 +132,17 @@
final int photoSize = getResources().getDimensionPixelSize(R.dimen.edit_photo_size);
- mName = (TextFieldsEditorView)findViewById(R.id.edit_name);
- mName.setMinimumHeight(photoSize);
+ mName = (StructuredNameEditorView)findViewById(R.id.edit_name);
mName.setDeletable(false);
+ mPhoneticName = (PhoneticNameEditorView)findViewById(R.id.edit_phonetic_name);
+
mFields = (ViewGroup)findViewById(R.id.sect_fields);
- mHeaderIcon = (ImageView) findViewById(R.id.header_icon);
- mHeaderAccountType = (TextView) findViewById(R.id.header_account_type);
- mHeaderAccountName = (TextView) findViewById(R.id.header_account_name);
+ mAccountContainer = findViewById(R.id.account);
+ mAccountIcon = (ImageView) findViewById(R.id.account_icon);
+ mAccountTypeTextView = (TextView) findViewById(R.id.account_type);
+ mAccountNameTextView = (TextView) findViewById(R.id.account_name);
mAddFieldButton = (Button) findViewById(R.id.button_add_field);
mAddFieldButton.setOnClickListener(new OnClickListener() {
@@ -161,33 +173,43 @@
// Make sure we have StructuredName
EntityModifier.ensureKindExists(state, type, StructuredName.CONTENT_ITEM_TYPE);
- // Fill in the header info
ValuesDelta values = state.getValues();
- String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
- CharSequence accountType = type.getDisplayLabel(mContext);
- if (TextUtils.isEmpty(accountType)) {
- accountType = mContext.getString(R.string.account_phone);
- }
- if (!TextUtils.isEmpty(accountName)) {
- mHeaderAccountName.setText(
- mContext.getString(R.string.from_account_format, accountName));
- }
- mHeaderAccountType.setText(mContext.getString(R.string.account_type_format, accountType));
- mHeaderIcon.setImageDrawable(type.getDisplayIcon(mContext));
-
mRawContactId = values.getAsLong(RawContacts._ID);
+ final ArrayList<Account> accounts =
+ AccountTypeManager.getInstance(mContext).getAccounts(true);
+ if (accounts.size() > 1) {
+ // Fill in the account info
+ String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
+ CharSequence accountType = type.getDisplayLabel(mContext);
+ if (TextUtils.isEmpty(accountType)) {
+ accountType = mContext.getString(R.string.account_phone);
+ }
+ if (!TextUtils.isEmpty(accountName)) {
+ mAccountNameTextView.setText(
+ mContext.getString(R.string.from_account_format, accountName));
+ }
+ mAccountTypeTextView.setText(
+ mContext.getString(R.string.account_type_format, accountType));
+ mAccountIcon.setImageDrawable(type.getDisplayIcon(mContext));
+ } else {
+ mAccountContainer.setVisibility(View.GONE);
+ }
+
// Show photo editor when supported
EntityModifier.ensureKindExists(state, type, Photo.CONTENT_ITEM_TYPE);
setHasPhotoEditor((type.getKindForMimetype(Photo.CONTENT_ITEM_TYPE) != null));
getPhotoEditor().setEnabled(isEnabled());
mName.setEnabled(isEnabled());
- mName.setEditorTextSize(
- mContext.getResources().getDimensionPixelSize(R.dimen.contact_name_text_size));
+ mName.setEditorTextSize(mContext.getResources().getDimensionPixelSize(
+ R.dimen.editor_structured_name_text_size));
+
+ mPhoneticName.setEnabled(isEnabled());
// Show and hide the appropriate views
mFields.setVisibility(View.VISIBLE);
mName.setVisibility(View.VISIBLE);
+ mPhoneticName.setVisibility(View.VISIBLE);
mGroupMembershipKind = type.getKindForMimetype(GroupMembership.CONTENT_ITEM_TYPE);
if (mGroupMembershipKind != null) {
@@ -206,7 +228,12 @@
if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
// Handle special case editor for structured name
final ValuesDelta primary = state.getPrimaryEntry(mimeType);
- mName.setValues(kind, primary, state, false, vig);
+ mName.setValues(
+ type.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME),
+ primary, state, false, vig);
+ mPhoneticName.setValues(
+ type.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME),
+ primary, state, false, vig);
} else if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
// Handle special case editor for photos
final ValuesDelta primary = state.getPrimaryEntry(mimeType);
@@ -230,6 +257,8 @@
mFields.addView(mGroupMembershipView);
}
+ updatePhoneticNameVisibility();
+
addToDefaultGroupIfNeeded();
mAddFieldButton.setEnabled(isEnabled());
@@ -307,6 +336,21 @@
return mName;
}
+ public TextFieldsEditorView getPhoneticNameEditor() {
+ return mPhoneticName;
+ }
+
+ private void updatePhoneticNameVisibility() {
+ boolean showByDefault =
+ getContext().getResources().getBoolean(R.bool.config_editor_include_phonetic_name);
+
+ if (showByDefault || mPhoneticName.hasData() || mPhoneticNameAdded) {
+ mPhoneticName.setVisibility(View.VISIBLE);
+ } else {
+ mPhoneticName.setVisibility(View.GONE);
+ }
+ }
+
@Override
public long getRawContactId() {
return mRawContactId;
@@ -323,18 +367,34 @@
if (child instanceof KindSectionView) {
final KindSectionView sectionView = (KindSectionView) child;
// not a list and already exists? ignore
- if (!sectionView.getKind().isList && sectionView.getEditorCount() != 0) {
+ DataKind kind = sectionView.getKind();
+ if (!kind.isList && sectionView.getEditorCount() != 0) {
continue;
}
+ if (DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME.equals(kind.mimeType)) {
+ continue;
+ }
+
+ if (DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(kind.mimeType)
+ && mPhoneticName.getVisibility() == View.VISIBLE) {
+ continue;
+ }
+
menu.add(Menu.NONE, fields.size(), Menu.NONE, sectionView.getTitle());
fields.add(sectionView);
}
}
+
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
final KindSectionView view = fields.get(item.getItemId());
- view.addItem();
+ if (DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(view.getKind().mimeType)) {
+ mPhoneticNameAdded = true;
+ updatePhoneticNameVisibility();
+ } else {
+ view.addItem();
+ }
return true;
}
});
diff --git a/src/com/android/contacts/editor/SelectAccountDialogFragment.java b/src/com/android/contacts/editor/SelectAccountDialogFragment.java
index 67c5f6e..65370f5 100644
--- a/src/com/android/contacts/editor/SelectAccountDialogFragment.java
+++ b/src/com/android/contacts/editor/SelectAccountDialogFragment.java
@@ -53,8 +53,7 @@
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
- final Listener target = (Listener) getTargetFragment();
- target.onAccountChosen(accountAdapter.getItem(which));
+ onAccountSelected(accountAdapter.getItem(which));
}
};
@@ -67,12 +66,27 @@
@Override
public void onCancel(DialogInterface dialog) {
super.onCancel(dialog);
- final Listener target = (Listener) getTargetFragment();
- target.onAccountSelectorCancelled();
+ final Fragment targetFragment = getTargetFragment();
+ if (targetFragment != null && targetFragment instanceof Listener) {
+ final Listener target = (Listener) targetFragment;
+ target.onAccountSelectorCancelled();
+ }
+ }
+
+ /**
+ * Calls {@link Listener#onAccountChosen(int, Account)} if the target fragment is castable
+ * to {@link Listener}. Subclasses can also overide to directly perform an operation
+ */
+ protected void onAccountSelected(Account account) {
+ final Fragment targetFragment = getTargetFragment();
+ if (targetFragment != null && targetFragment instanceof Listener) {
+ final Listener target = (Listener) targetFragment;
+ target.onAccountChosen(getTargetRequestCode(), account);
+ }
}
public interface Listener {
- void onAccountChosen(Account account);
+ void onAccountChosen(int requestCode, Account account);
void onAccountSelectorCancelled();
}
}
diff --git a/src/com/android/contacts/editor/StructuredNameEditorView.java b/src/com/android/contacts/editor/StructuredNameEditorView.java
new file mode 100644
index 0000000..5a2ffd3
--- /dev/null
+++ b/src/com/android/contacts/editor/StructuredNameEditorView.java
@@ -0,0 +1,241 @@
+/*
+ * 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.editor;
+
+import com.android.contacts.model.DataKind;
+import com.android.contacts.model.EntityDelta;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.android.contacts.util.NameConverter;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A dedicated editor for structured name. When the user collapses/expands
+ * the structured name, it will reparse or recompose the name, but only
+ * if the user has made changes. This distinction will be particularly
+ * obvious if the name has a non-standard structure. Consider this structure:
+ * first name="John Doe", family name="". As long as the user does not change
+ * the full name, expand and collapse will preserve this. However, if the user
+ * changes "John Doe" to "Jane Doe" and then expands the view, we will reparse
+ * and show first name="Jane", family name="Doe".
+ */
+public class StructuredNameEditorView extends TextFieldsEditorView {
+
+ private ContentValues mSnapshot;
+ private boolean mChanged;
+
+ public StructuredNameEditorView(Context context) {
+ super(context);
+ }
+
+ public StructuredNameEditorView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public StructuredNameEditorView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public void setValues(DataKind kind, ValuesDelta entry, EntityDelta state, boolean readOnly,
+ ViewIdGenerator vig) {
+ super.setValues(kind, entry, state, readOnly, vig);
+ if (mSnapshot == null) {
+ mSnapshot = new ContentValues(getValues().getCompleteValues());
+ mChanged = entry.isInsert();
+ } else {
+ mChanged = false;
+ }
+ }
+
+ @Override
+ public void onFieldChanged(String column, String value) {
+ if (!isFieldChanged(column, value)) {
+ return;
+ }
+
+ mChanged = true;
+
+ if (hasShortAndLongForms()) {
+ if (areOptionalFieldsVisible()) {
+ eraseFullName(getValues());
+ } else {
+ eraseStructuredName(getValues());
+ }
+ }
+
+ super.onFieldChanged(column, value);
+ }
+
+ @Override
+ protected void onOptionalFieldVisibilityChange() {
+ if (hasShortAndLongForms()) {
+ if (areOptionalFieldsVisible()) {
+ switchFromFullNameToStructuredName();
+ } else {
+ switchFromStructuredNameToFullName();
+ }
+ }
+
+ super.onOptionalFieldVisibilityChange();
+ }
+
+ private void switchFromFullNameToStructuredName() {
+ ValuesDelta values = getValues();
+
+ if (!mChanged) {
+ for (String field : NameConverter.STRUCTURED_NAME_FIELDS) {
+ values.put(field, mSnapshot.getAsString(field));
+ }
+ return;
+ }
+
+ String displayName = values.getAsString(StructuredName.DISPLAY_NAME);
+ Map<String, String> structuredNameMap = NameConverter.displayNameToStructuredName(
+ getContext(), displayName);
+ if (!structuredNameMap.isEmpty()) {
+ eraseFullName(values);
+ for (String field : structuredNameMap.keySet()) {
+ values.put(field, structuredNameMap.get(field));
+ }
+ }
+
+ mSnapshot.clear();
+ mSnapshot.putAll(values.getCompleteValues());
+ mSnapshot.put(StructuredName.DISPLAY_NAME, displayName);
+ }
+
+ private void switchFromStructuredNameToFullName() {
+ ValuesDelta values = getValues();
+
+ if (!mChanged) {
+ values.put(StructuredName.DISPLAY_NAME,
+ mSnapshot.getAsString(StructuredName.DISPLAY_NAME));
+ return;
+ }
+
+ Map<String, String> structuredNameMap = valuesToStructuredNameMap(values);
+ String displayName = NameConverter.structuredNameToDisplayName(getContext(),
+ structuredNameMap);
+ if (!TextUtils.isEmpty(displayName)) {
+ eraseStructuredName(values);
+ values.put(StructuredName.DISPLAY_NAME, displayName);
+ }
+
+ mSnapshot.clear();
+ mSnapshot.put(StructuredName.DISPLAY_NAME, values.getAsString(StructuredName.DISPLAY_NAME));
+ for (String field : structuredNameMap.keySet()) {
+ mSnapshot.put(field, structuredNameMap.get(field));
+ }
+ }
+
+ private Map<String, String> valuesToStructuredNameMap(ValuesDelta values) {
+ Map<String, String> structuredNameMap = new HashMap<String, String>();
+ for (String key : NameConverter.STRUCTURED_NAME_FIELDS) {
+ structuredNameMap.put(key, values.getAsString(key));
+ }
+ return structuredNameMap;
+ }
+
+ private void eraseFullName(ValuesDelta values) {
+ values.putNull(StructuredName.DISPLAY_NAME);
+ }
+
+ private void eraseStructuredName(ValuesDelta values) {
+ for (String field : NameConverter.STRUCTURED_NAME_FIELDS) {
+ values.putNull(field);
+ }
+ }
+
+ private static void appendQueryParameter(Uri.Builder builder, String field, String value) {
+ if (!TextUtils.isEmpty(value)) {
+ builder.appendQueryParameter(field, value);
+ }
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ SavedState state = new SavedState(super.onSaveInstanceState());
+ state.mChanged = mChanged;
+ state.mSnapshot = mSnapshot;
+ return state;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ SavedState ss = (SavedState) state;
+ super.onRestoreInstanceState(ss.mSuperState);
+
+ mChanged = ss.mChanged;
+ mSnapshot = ss.mSnapshot;
+ }
+
+ private static class SavedState implements Parcelable {
+ public boolean mChanged;
+ public ContentValues mSnapshot;
+ public Parcelable mSuperState;
+
+ SavedState(Parcelable superState) {
+ mSuperState = superState;
+ }
+
+ private SavedState(Parcel in) {
+ ClassLoader loader = getClass().getClassLoader();
+ mSuperState = in.readParcelable(loader);
+
+ mChanged = in.readInt() != 0;
+ mSnapshot = in.readParcelable(loader);
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeParcelable(mSuperState, 0);
+
+ out.writeInt(mChanged ? 1 : 0);
+ out.writeParcelable(mSnapshot, 0);
+ }
+
+ @SuppressWarnings({"unused"})
+ public static final Parcelable.Creator<SavedState> CREATOR
+ = new Parcelable.Creator<SavedState>() {
+ @Override
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ @Override
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+ }
+}
diff --git a/src/com/android/contacts/editor/TextFieldsEditorView.java b/src/com/android/contacts/editor/TextFieldsEditorView.java
index 1a930a1..04a9485 100644
--- a/src/com/android/contacts/editor/TextFieldsEditorView.java
+++ b/src/com/android/contacts/editor/TextFieldsEditorView.java
@@ -18,40 +18,49 @@
import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType.DataKind;
import com.android.contacts.model.AccountType.EditField;
+import com.android.contacts.model.DataKind;
import com.android.contacts.model.EntityDelta;
import com.android.contacts.model.EntityDelta.ValuesDelta;
-import com.android.contacts.util.ThemeUtils;
+import com.android.contacts.util.NameConverter;
import android.content.Context;
import android.content.Entity;
-import android.content.res.Resources;
import android.graphics.Rect;
+import android.graphics.Typeface;
import android.os.Parcel;
import android.os.Parcelable;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.telephony.PhoneNumberFormattingTextWatcher;
import android.text.Editable;
import android.text.InputType;
+import android.text.Spannable;
+import android.text.TextUtils;
import android.text.TextWatcher;
+import android.text.style.StyleSpan;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.EditText;
-import android.widget.ImageButton;
+import android.widget.ImageView;
import android.widget.LinearLayout;
+import java.util.Map;
+
/**
- * Simple editor that handles labels and any {@link EditField} defined for
- * the entry. Uses {@link ValuesDelta} to read any existing
- * {@link Entity} values, and to correctly write any changes values.
+ * Simple editor that handles labels and any {@link EditField} defined for the
+ * entry. Uses {@link ValuesDelta} to read any existing {@link Entity} values,
+ * and to correctly write any changes values.
*/
public class TextFieldsEditorView extends LabeledEditorView {
private EditText[] mFieldEditTexts = null;
- private ImageButton mMoreOrLess;
+ private ViewGroup mFields = null;
+ private View mExpansionViewContainer;
+ private ImageView mExpansionView;
private boolean mHideOptional = true;
private boolean mHasShortAndLongForms;
- private int mEditorTextSize;
+ private int mEditorTextSize = 0;
public TextFieldsEditorView(Context context) {
super(context);
@@ -65,97 +74,46 @@
super(context, attrs, defStyle);
}
- public void setEditorTextSize(int textSize) {
- this.mEditorTextSize = textSize;
- }
-
+ /** {@inheritDoc} */
@Override
- protected int getLineItemCount() {
- int count = mFieldEditTexts == null ? 0 : mFieldEditTexts.length;
- return Math.max(count, super.getLineItemCount());
- }
+ protected void onFinishInflate() {
+ super.onFinishInflate();
- @Override
- protected boolean isLineItemVisible(int row) {
- return mFieldEditTexts != null && mFieldEditTexts[row].getVisibility() != View.GONE;
- }
+ setDrawingCacheEnabled(true);
+ setAlwaysDrawnWithCacheEnabled(true);
- @Override
- public int getBaseline(int row) {
- int baseline = super.getBaseline(row);
- if (mFieldEditTexts != null) {
- EditText editText = mFieldEditTexts[row];
- // The text field will be centered vertically in the corresponding line item
- int lineItemHeight = getLineItemHeight(row);
- int offset = (lineItemHeight - editText.getMeasuredHeight()) / 2;
- baseline = Math.max(baseline, offset + editText.getBaseline());
- }
- return baseline;
- }
+ mFields = (ViewGroup) findViewById(R.id.editors);
+ mExpansionView = (ImageView) findViewById(R.id.expansion_view);
+ mExpansionViewContainer = findViewById(R.id.expansion_view_container);
+ mExpansionViewContainer.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Save focus
+ final View focusedChild = getFocusedChild();
+ final int focusedViewId = focusedChild == null ? -1 : focusedChild.getId();
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
+ // Reconfigure GUI
+ mHideOptional = !mHideOptional;
+ onOptionalFieldVisibilityChange();
+ rebuildValues();
- int l1 = getPaddingLeft();
- int t1 = getPaddingTop();
- int r1 = getMeasuredWidth() - getPaddingRight();
-
- if ((mMoreOrLess != null)) {
- mMoreOrLess.layout(
- r1 - mMoreOrLess.getMeasuredWidth(), t1,
- r1, t1 + mMoreOrLess.getMeasuredHeight());
- }
-
- // Subtract buttons if necessary
- final int labelWidth = (getLabel() != null) ? getLabel().getMeasuredWidth() : 0;
- final int deleteWidth = (getDelete() != null) ? getDelete().getMeasuredWidth() : 0;
- final int moreOrLessWidth = mMoreOrLess != null ? mMoreOrLess.getMeasuredWidth() : 0;
- final int r2 = r1 - Math.max(deleteWidth, moreOrLessWidth) - labelWidth;
-
- // Layout text fields
- int y = t1;
- if (mFieldEditTexts != null) {
- for (int i = 0; i < mFieldEditTexts.length; i++) {
- int baseline = getBaseline(i);
- EditText editText = mFieldEditTexts[i];
- if (editText.getVisibility() != View.GONE) {
- int height = editText.getMeasuredHeight();
- int top = t1 + y + baseline - editText.getBaseline();
- editText.layout(
- l1, top,
- r2, top + height);
- y += getLineItemHeight(i);
+ // Restore focus
+ View newFocusView = findViewById(focusedViewId);
+ if (newFocusView == null || newFocusView.getVisibility() == GONE) {
+ // find first visible child
+ newFocusView = TextFieldsEditorView.this;
}
+ newFocusView.requestFocus();
}
- }
+ });
}
- @Override
- protected int getLineItemHeight(int row) {
- int fieldHeight = 0;
- int buttonHeight = 0;
-
- boolean lastLineItem = true;
- if (mFieldEditTexts != null) {
- fieldHeight = mFieldEditTexts[row].getMeasuredHeight();
- lastLineItem = (row == mFieldEditTexts.length - 1);
- }
-
- // Ensure there is enough space for the more/less button
- if (row == 0) {
- final int moreOrLessHeight = mMoreOrLess != null ? mMoreOrLess.getMeasuredHeight() : 0;
- buttonHeight += moreOrLessHeight;
- }
-
- // Ensure there is enough space for the minus button
- if (lastLineItem) {
- View deleteButton = getDelete();
- final int deleteHeight = (deleteButton != null) ? deleteButton.getMeasuredHeight() : 0;
- buttonHeight += deleteHeight;
- }
-
- return Math.max(Math.max(buttonHeight, fieldHeight), super.getLineItemHeight(row));
+ /**
+ * Set the text size of the value of all fields in this class, which will override the default
+ * text appearance style for the associated {@link DataKind}.
+ */
+ public void setEditorTextSize(int textSize) {
+ mEditorTextSize = textSize;
}
@Override
@@ -167,59 +125,20 @@
mFieldEditTexts[index].setEnabled(!isReadOnly() && enabled);
}
}
- if (mMoreOrLess != null) mMoreOrLess.setEnabled(!isReadOnly() && enabled);
+ mExpansionView.setEnabled(!isReadOnly() && enabled);
}
/**
* Creates or removes the type/label button. Doesn't do anything if already correctly configured
*/
- private void setupMoreOrLessButton(boolean shouldExist, boolean collapsed) {
+ private void setupExpansionView(boolean shouldExist, boolean collapsed) {
if (shouldExist) {
- if (mMoreOrLess == null) {
- mMoreOrLess = new ImageButton(mContext);
- mMoreOrLess.setBackgroundResource(
- ThemeUtils.getSelectableItemBackground(mContext.getTheme()));
- final Resources resources = mContext.getResources();
- mMoreOrLess.setPadding(
- resources.getDimensionPixelOffset(
- R.dimen.editor_round_button_padding_left),
- resources.getDimensionPixelOffset(
- R.dimen.editor_round_button_padding_top),
- resources.getDimensionPixelOffset(
- R.dimen.editor_round_button_padding_right),
- resources.getDimensionPixelOffset(
- R.dimen.editor_round_button_padding_bottom));
- mMoreOrLess.setLayoutParams(
- new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
- mMoreOrLess.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- // Save focus
- final View focusedChild = getFocusedChild();
- final int focusedViewId = focusedChild == null ? -1 : focusedChild.getId();
-
- // Reconfigure GUI
- mHideOptional = !mHideOptional;
- onOptionalFieldVisibilityChange();
- rebuildValues();
-
- // Restore focus
- View newFocusView = findViewById(focusedViewId);
- if (newFocusView == null || newFocusView.getVisibility() == GONE) {
- // find first visible child
- newFocusView = TextFieldsEditorView.this;
- }
- newFocusView.requestFocus();
- }
- });
- addView(mMoreOrLess);
- }
- mMoreOrLess.setImageResource(collapsed
+ mExpansionViewContainer.setVisibility(View.VISIBLE);
+ mExpansionView.setImageResource(collapsed
? R.drawable.ic_menu_expander_minimized_holo_light
: R.drawable.ic_menu_expander_maximized_holo_light);
- } else if (mMoreOrLess != null) {
- removeView(mMoreOrLess);
- mMoreOrLess = null;
+ } else {
+ mExpansionViewContainer.setVisibility(View.GONE);
}
}
@@ -250,7 +169,7 @@
// Remove edit texts that we currently have
if (mFieldEditTexts != null) {
for (EditText fieldEditText : mFieldEditTexts) {
- removeView(fieldEditText);
+ mFields.removeView(fieldEditText);
}
}
boolean hidePossible = false;
@@ -262,10 +181,11 @@
final EditText fieldView = new EditText(mContext);
fieldView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT));
- fieldView.setGravity(Gravity.TOP);
+ fieldView.setTextAppearance(getContext(), kind.textAppearanceResourceId);
if (mEditorTextSize != 0) {
fieldView.setTextSize(mEditorTextSize);
}
+ fieldView.setGravity(Gravity.TOP);
mFieldEditTexts[index] = fieldView;
fieldView.setId(vig.getId(state, kind, entry, index));
if (field.titleRes > 0) {
@@ -273,6 +193,9 @@
}
int inputType = field.inputType;
fieldView.setInputType(inputType);
+ if (field.isFullName) {
+ fieldView.addTextChangedListener(new NameFormattingTextWatcher());
+ }
if (inputType == InputType.TYPE_CLASS_PHONE) {
fieldView.addTextChangedListener(new PhoneNumberFormattingTextWatcher(
ContactsUtils.getCurrentCountryIso(mContext)));
@@ -319,12 +242,23 @@
hidePossible = hidePossible || couldHide;
}
- addView(fieldView);
+ mFields.addView(fieldView);
}
// When hiding fields, place expandable
- setupMoreOrLessButton(hidePossible, mHideOptional);
- if (mMoreOrLess != null) mMoreOrLess.setEnabled(!readOnly && isEnabled());
+ setupExpansionView(hidePossible, mHideOptional);
+ mExpansionView.setEnabled(!readOnly && isEnabled());
+ }
+
+ @Override
+ public boolean isEmpty() {
+ for (int i = 0; i < mFields.getChildCount(); i++) {
+ EditText editText = (EditText) mFields.getChildAt(i);
+ if (!TextUtils.isEmpty(editText.getText())) {
+ return false;
+ }
+ }
+ return true;
}
/**
@@ -364,7 +298,7 @@
ss.mHideOptional = mHideOptional;
- final int numChildren = mFieldEditTexts.length;
+ final int numChildren = mFieldEditTexts == null ? 0 : mFieldEditTexts.length;
ss.mVisibilities = new int[numChildren];
for (int i = 0; i < numChildren; i++) {
ss.mVisibilities[i] = mFieldEditTexts[i].getVisibility();
@@ -424,4 +358,60 @@
}
};
}
+
+ private class NameFormattingTextWatcher implements TextWatcher {
+
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ String displayName = s.toString();
+ Map<String, String> structuredName = NameConverter.displayNameToStructuredName(
+ getContext(), displayName);
+ String givenName = structuredName.get(StructuredName.GIVEN_NAME);
+ if (!TextUtils.isEmpty(givenName)) {
+ int spanStart = -1;
+ int spanEnd = -1;
+ if (displayName.startsWith(givenName + " ")) {
+ spanStart = 0;
+ spanEnd = givenName.length();
+ } else {
+ spanStart = displayName.lastIndexOf(" " + givenName);
+ if (spanStart > -1) {
+ spanStart++;
+ spanEnd = spanStart + givenName.length();
+ }
+ }
+
+ // If the requested range is already bolded, don't make any changes.
+ if (spanStart > -1) {
+ StyleSpan[] existingSpans = s.getSpans(0, s.length(), StyleSpan.class);
+ for (StyleSpan span : existingSpans) {
+ if (span.getStyle() == Typeface.BOLD
+ && s.getSpanStart(span.getUnderlying()) == spanStart
+ && s.getSpanEnd(span.getUnderlying()) == spanEnd) {
+ // Nothing to do - the correct portion is already bolded.
+ return;
+ }
+ }
+
+ // Clear any existing bold style spans.
+ for (StyleSpan span : existingSpans) {
+ if (span.getStyle() == Typeface.BOLD) {
+ s.removeSpan(span);
+ }
+ }
+
+ // Set the new bold span.
+ s.setSpan(new StyleSpan(Typeface.BOLD), spanStart, spanEnd,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+ }
+ }
}
diff --git a/src/com/android/contacts/editor/ViewIdGenerator.java b/src/com/android/contacts/editor/ViewIdGenerator.java
index 93bb002..c3cd08b 100644
--- a/src/com/android/contacts/editor/ViewIdGenerator.java
+++ b/src/com/android/contacts/editor/ViewIdGenerator.java
@@ -16,8 +16,8 @@
package com.android.contacts.editor;
+import com.android.contacts.model.DataKind;
import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.AccountType.DataKind;
import com.android.contacts.model.EntityDelta.ValuesDelta;
import android.os.Bundle;
diff --git a/src/com/android/contacts/format/FormatUtils.java b/src/com/android/contacts/format/FormatUtils.java
new file mode 100644
index 0000000..ac34d6d
--- /dev/null
+++ b/src/com/android/contacts/format/FormatUtils.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.format;
+
+import android.database.CharArrayBuffer;
+import android.graphics.Typeface;
+import android.text.SpannableString;
+import android.text.style.StyleSpan;
+
+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.
+ */
+ 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;
+ }
+}
diff --git a/src/com/android/contacts/group/GroupBrowseListAdapter.java b/src/com/android/contacts/group/GroupBrowseListAdapter.java
new file mode 100644
index 0000000..bccc207
--- /dev/null
+++ b/src/com/android/contacts/group/GroupBrowseListAdapter.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.group;
+
+import com.android.contacts.R;
+import com.android.contacts.GroupMetaData;
+
+import android.content.Context;
+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 java.util.List;
+
+/**
+ * Adapter to populate the list of groups.
+ */
+public class GroupBrowseListAdapter extends BaseAdapter {
+
+ private LayoutInflater mLayoutInflater;
+ private List<GroupMetaData> mGroupList;
+
+ public GroupBrowseListAdapter(Context context, List<GroupMetaData> groupList) {
+ mLayoutInflater = LayoutInflater.from(context);
+ mGroupList = groupList;
+ }
+
+ @Override
+ public int getCount() {
+ return mGroupList.size();
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return getItem(position).getGroupId();
+ }
+
+ @Override
+ public GroupMetaData getItem(int position) {
+ return mGroupList.get(position);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = mLayoutInflater.inflate(R.layout.group_browse_list_item, parent, false);
+ }
+ GroupMetaData group = getItem(position);
+ ImageView icon = (ImageView) convertView.findViewById(R.id.icon);
+ TextView label = (TextView) convertView.findViewById(R.id.label);
+ TextView account = (TextView) convertView.findViewById(R.id.account);
+ icon.setImageResource(R.drawable.ic_menu_display_all_holo_light);
+ label.setText(group.getTitle());
+ account.setText(group.getAccountName());
+
+ // Set the tag to be the GroupMetaData object, in order to extract group attributes from the
+ // view later.
+ convertView.setTag(group);
+ return convertView;
+ }
+
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/group/GroupBrowseListFragment.java b/src/com/android/contacts/group/GroupBrowseListFragment.java
new file mode 100644
index 0000000..d9d020e
--- /dev/null
+++ b/src/com/android/contacts/group/GroupBrowseListFragment.java
@@ -0,0 +1,194 @@
+/*
+ * 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.group;
+
+import com.android.contacts.GroupMetaData;
+import com.android.contacts.GroupMetaDataLoader;
+import com.android.contacts.R;
+import com.android.contacts.activities.GroupDetailActivity;
+
+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.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.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ListView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Fragment to display the list of groups.
+ */
+public class GroupBrowseListFragment extends Fragment
+ implements OnFocusChangeListener, OnTouchListener {
+
+ private static final String TAG = "GroupBrowseListFragment";
+
+ private static final int LOADER_GROUPS = 1;
+
+ private Context mContext;
+ private Cursor mGroupListCursor;
+ private List<GroupMetaData> mGroupList = new ArrayList<GroupMetaData>();
+
+ private View mRootView;
+ private ListView mListView;
+ private View mEmptyView;
+
+ public GroupBrowseListFragment() {
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ mRootView = inflater.inflate(R.layout.group_browse_list_fragment, null);
+ mListView = (ListView) mRootView.findViewById(R.id.list);
+ mListView.setOnFocusChangeListener(this);
+ mListView.setOnTouchListener(this);
+ mEmptyView = mRootView.findViewById(R.id.empty);
+ return mRootView;
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ mContext = activity;
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ mContext = null;
+ }
+
+ @Override
+ public void onStart() {
+ getLoaderManager().initLoader(LOADER_GROUPS, null, mGroupLoaderListener);
+ super.onStart();
+ }
+
+ /**
+ * The listener for the group meta data loader.
+ */
+ private final LoaderManager.LoaderCallbacks<Cursor> mGroupLoaderListener =
+ new LoaderCallbacks<Cursor>() {
+
+ @Override
+ public CursorLoader onCreateLoader(int id, Bundle args) {
+ return new GroupMetaDataLoader(mContext);
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ mGroupListCursor = data;
+ bindGroupList();
+ }
+
+ public void onLoaderReset(Loader<Cursor> loader) {
+ }
+ };
+
+ private void bindGroupList() {
+ if (mGroupListCursor == null) {
+ return;
+ }
+ mGroupList.clear();
+ mGroupListCursor.moveToPosition(-1);
+ while (mGroupListCursor.moveToNext()) {
+ String accountName = mGroupListCursor.getString(GroupMetaDataLoader.ACCOUNT_NAME);
+ String accountType = mGroupListCursor.getString(GroupMetaDataLoader.ACCOUNT_TYPE);
+ long groupId = mGroupListCursor.getLong(GroupMetaDataLoader.GROUP_ID);
+ String title = mGroupListCursor.getString(GroupMetaDataLoader.TITLE);
+ boolean defaultGroup = mGroupListCursor.isNull(GroupMetaDataLoader.AUTO_ADD)
+ ? false
+ : mGroupListCursor.getInt(GroupMetaDataLoader.AUTO_ADD) != 0;
+ boolean favorites = mGroupListCursor.isNull(GroupMetaDataLoader.FAVORITES)
+ ? false
+ : mGroupListCursor.getInt(GroupMetaDataLoader.FAVORITES) != 0;
+
+ // TODO: Separate groups according to account name and type.
+ mGroupList.add(new GroupMetaData(
+ accountName, accountType, groupId, title, defaultGroup, favorites));
+ }
+
+ mListView.setAdapter(new GroupBrowseListAdapter(mContext, mGroupList));
+ mListView.setEmptyView(mEmptyView);
+ mListView.setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ startGroupDetailActivity((GroupMetaData) view.getTag());
+ }
+ });
+ }
+
+ private void startGroupDetailActivity(GroupMetaData group) {
+ if (group == null) {
+ return;
+ }
+ Intent intent = new Intent(mContext, GroupDetailActivity.class);
+ intent.putExtra(GroupDetailActivity.KEY_ACCOUNT_TYPE, group.getAccountType());
+ intent.putExtra(GroupDetailActivity.KEY_ACCOUNT_NAME, group.getAccountName());
+ intent.putExtra(GroupDetailActivity.KEY_GROUP_ID, group.getGroupId());
+ intent.putExtra(GroupDetailActivity.KEY_GROUP_TITLE, group.getTitle());
+ mContext.startActivity(intent);
+ }
+
+ private void hideSoftKeyboard() {
+ if (mContext == null) {
+ return;
+ }
+ // 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;
+ }
+}
diff --git a/src/com/android/contacts/group/GroupDetailFragment.java b/src/com/android/contacts/group/GroupDetailFragment.java
new file mode 100644
index 0000000..98babac
--- /dev/null
+++ b/src/com/android/contacts/group/GroupDetailFragment.java
@@ -0,0 +1,180 @@
+/*
+ * 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.group;
+
+import com.android.contacts.ContactPhotoManager;
+import com.android.contacts.R;
+import com.android.contacts.activities.GroupDetailActivity;
+import com.android.contacts.list.ContactListAdapter;
+import com.android.contacts.list.ContactListFilter;
+import com.android.contacts.list.DefaultContactListAdapter;
+
+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.provider.ContactsContract;
+import android.provider.ContactsContract.Directory;
+import android.view.LayoutInflater;
+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.OnItemClickListener;
+import android.widget.ListView;
+
+/**
+ * Displays the details of a group and shows a list of actions possible for the group.
+ */
+public class GroupDetailFragment extends Fragment implements OnScrollListener {
+
+ private static final String TAG = "GroupDetailFragment";
+
+ private static final int LOADER_MEMBERS = 0;
+
+ private Context mContext;
+
+ private View mRootView;
+ private ListView mMemberListView;
+
+ private ContactListAdapter mAdapter;
+ private ContactPhotoManager mPhotoManager;
+
+ public GroupDetailFragment() {
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ mContext = activity;
+ configurePhotoLoader();
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ mContext = null;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
+ mRootView = inflater.inflate(R.layout.group_detail_fragment, container, false);
+ mMemberListView = (ListView) mRootView.findViewById(R.id.member_list);
+ mMemberListView.setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ // TODO: Open contact detail for this person
+ }
+ });
+ return mRootView;
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ Intent intent = getActivity().getIntent();
+ String accountType = intent.getStringExtra(GroupDetailActivity.KEY_ACCOUNT_TYPE);
+ String accountName = intent.getStringExtra(GroupDetailActivity.KEY_ACCOUNT_NAME);
+ long groupId = intent.getLongExtra(GroupDetailActivity.KEY_GROUP_ID, -1);
+ String groupTitle = intent.getStringExtra(GroupDetailActivity.KEY_GROUP_TITLE);
+
+ configureAdapter(accountType, accountName, groupId, groupTitle);
+ startGroupMembersLoader();
+ }
+
+ private void configureAdapter(String accountType, String accountName,
+ long groupId, String groupTitle) {
+ mAdapter = new DefaultContactListAdapter(getActivity());
+ mAdapter.setSectionHeaderDisplayEnabled(false);
+ mAdapter.setDisplayPhotos(true);
+ mAdapter.setHasHeader(0, false);
+ mAdapter.setQuickContactEnabled(false);
+ mAdapter.setPinnedPartitionHeadersEnabled(false);
+ mAdapter.setContactNameDisplayOrder(ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY);
+ mAdapter.setSortOrder(ContactsContract.Preferences.SORT_ORDER_PRIMARY);
+ mAdapter.setPhotoLoader(mPhotoManager);
+ mAdapter.setFilter(new ContactListFilter(accountType, accountName, groupId, "", false,
+ groupTitle));
+ mMemberListView.setAdapter(mAdapter);
+ }
+
+ private void configurePhotoLoader() {
+ if (mContext != null) {
+ if (mPhotoManager == null) {
+ mPhotoManager = ContactPhotoManager.getInstance(mContext);
+ }
+ if (mMemberListView != null) {
+ mMemberListView.setOnScrollListener(this);
+ }
+ if (mAdapter != null) {
+ mAdapter.setPhotoLoader(mPhotoManager);
+ }
+ }
+ }
+
+ /**
+ * Start the loader to retrieve the list of group members.
+ */
+ private void startGroupMembersLoader() {
+ getLoaderManager().destroyLoader(LOADER_MEMBERS);
+ getLoaderManager().restartLoader(LOADER_MEMBERS, null, mGroupMemberListLoaderListener);
+ }
+
+ /**
+ * The listener for the group members list loader
+ */
+ private final LoaderManager.LoaderCallbacks<Cursor> mGroupMemberListLoaderListener =
+ new LoaderCallbacks<Cursor>() {
+
+ @Override
+ public CursorLoader onCreateLoader(int id, Bundle args) {
+ CursorLoader loader = new CursorLoader(mContext, null, null, null, null, null);
+ mAdapter.configureLoader(loader, Directory.DEFAULT);
+ return loader;
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ mAdapter.changeCursor(loader.getId(), data);
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {}
+ };
+
+ @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 {
+ mPhotoManager.resume();
+ }
+ }
+}
diff --git a/src/com/android/contacts/interactions/ContactDeletionInteraction.java b/src/com/android/contacts/interactions/ContactDeletionInteraction.java
index bc78e87..f195c2f 100644
--- a/src/com/android/contacts/interactions/ContactDeletionInteraction.java
+++ b/src/com/android/contacts/interactions/ContactDeletionInteraction.java
@@ -50,6 +50,7 @@
private static final String KEY_ACTIVE = "active";
private static final String KEY_CONTACT_URI = "contactUri";
+ private static final String KEY_FINISH_WHEN_DONE = "finishWhenDone";
public static final String ARG_CONTACT_URI = "contactUri";
private static final String[] ENTITY_PROJECTION = new String[] {
@@ -66,6 +67,7 @@
private boolean mActive;
private Uri mContactUri;
+ private boolean mFinishActivityWhenDone;
private Context mContext;
private AlertDialog mDialog;
@@ -73,16 +75,23 @@
// Visible for testing
int mMessageId;
- public static ContactDeletionInteraction start(Activity activity, Uri contactUri) {
+ public static ContactDeletionInteraction start(
+ Activity activity, Uri contactUri, boolean finishActivityWhenDone) {
+ if (contactUri == null) {
+ return null;
+ }
+
FragmentManager fragmentManager = activity.getFragmentManager();
ContactDeletionInteraction fragment =
(ContactDeletionInteraction) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
if (fragment == null) {
fragment = new ContactDeletionInteraction();
fragment.setContactUri(contactUri);
+ fragment.setFinishActivityWhenDone(finishActivityWhenDone);
fragmentManager.beginTransaction().add(fragment, FRAGMENT_TAG).commit();
} else {
fragment.setContactUri(contactUri);
+ fragment.setFinishActivityWhenDone(finishActivityWhenDone);
}
return fragment;
}
@@ -93,6 +102,16 @@
mContext = activity;
}
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ if (mDialog != null && mDialog.isShowing()) {
+ mDialog.setOnDismissListener(null);
+ mDialog.dismiss();
+ mDialog = null;
+ }
+ }
+
public void setContactUri(Uri contactUri) {
mContactUri = contactUri;
mActive = true;
@@ -103,6 +122,11 @@
}
}
+ private void setFinishActivityWhenDone(boolean finishActivityWhenDone) {
+ this.mFinishActivityWhenDone = finishActivityWhenDone;
+
+ }
+
/* Visible for testing */
boolean isStarted() {
return isAdded();
@@ -119,6 +143,14 @@
}
@Override
+ public void onStop() {
+ super.onStop();
+ if (mDialog != null) {
+ mDialog.hide();
+ }
+ }
+
+ @Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
Uri contactUri = args.getParcelable(ARG_CONTACT_URI);
return new CursorLoader(mContext,
@@ -174,8 +206,13 @@
final Uri contactUri = Contacts.getLookupUri(contactId, lookupKey);
showDialog(mMessageId, contactUri);
+
+ // We don't want onLoadFinished() calls any more, which may come when the database is
+ // updating.
+ getLoaderManager().destroyLoader(R.id.dialog_delete_contact_loader_id);
}
+ @Override
public void onLoaderReset(Loader<Cursor> loader) {
}
@@ -203,7 +240,6 @@
public void onDismiss(DialogInterface dialog) {
mActive = false;
mDialog = null;
- getLoaderManager().destroyLoader(R.id.dialog_delete_contact_loader_id);
}
@Override
@@ -211,6 +247,7 @@
super.onSaveInstanceState(outState);
outState.putBoolean(KEY_ACTIVE, mActive);
outState.putParcelable(KEY_CONTACT_URI, mContactUri);
+ outState.putBoolean(KEY_FINISH_WHEN_DONE, mFinishActivityWhenDone);
}
@Override
@@ -219,10 +256,14 @@
if (savedInstanceState != null) {
mActive = savedInstanceState.getBoolean(KEY_ACTIVE);
mContactUri = savedInstanceState.getParcelable(KEY_CONTACT_URI);
+ mFinishActivityWhenDone = savedInstanceState.getBoolean(KEY_FINISH_WHEN_DONE);
}
}
protected void doDeleteContact(Uri contactUri) {
mContext.startService(ContactSaveService.createDeleteContactIntent(mContext, contactUri));
+ if (isAdded() && mFinishActivityWhenDone) {
+ getActivity().finish();
+ }
}
}
diff --git a/src/com/android/contacts/interactions/ImportExportInteraction.java b/src/com/android/contacts/interactions/ImportExportDialogFragment.java
similarity index 62%
rename from src/com/android/contacts/interactions/ImportExportInteraction.java
rename to src/com/android/contacts/interactions/ImportExportDialogFragment.java
index bd8ac16..4e22fa2 100644
--- a/src/com/android/contacts/interactions/ImportExportInteraction.java
+++ b/src/com/android/contacts/interactions/ImportExportDialogFragment.java
@@ -17,14 +17,16 @@
package com.android.contacts.interactions;
import com.android.contacts.R;
+import com.android.contacts.editor.SelectAccountDialogFragment;
import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.util.AccountSelectionUtil;
import com.android.contacts.vcard.ExportVCardActivity;
import android.accounts.Account;
-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;
@@ -35,7 +37,6 @@
import android.provider.ContactsContract.Contacts;
import android.telephony.TelephonyManager;
import android.util.Log;
-import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -46,70 +47,39 @@
import java.util.List;
/**
- * An interaction invoked to import/export contacts.
+ * An dialog invoked to import/export contacts.
*/
-public class ImportExportInteraction {
-
- private static final String TAG = "ImportExportInteraction";
+public class ImportExportDialogFragment extends DialogFragment {
+ public static final String TAG = "ImportExportDialogFragment";
private final String[] LOOKUP_PROJECTION = new String[] {
Contacts.LOOKUP_KEY
};
- private final Context mContext;
-
- public ImportExportInteraction(Context context) {
- this.mContext = context;
+ /** Preferred way to show this dialog */
+ public static void show(FragmentManager fragmentManager) {
+ final ImportExportDialogFragment fragment = new ImportExportDialogFragment();
+ fragment.show(fragmentManager, ImportExportDialogFragment.TAG);
}
- /**
- * Creates a {@link Dialog} that allows the user to choose between a bulk import
- * and bulk export task across all contacts.
- */
- public void startInteraction() {
- showDialog(R.id.dialog_import_export_options, null);
- }
-
- public Dialog onCreateDialog(int id, Bundle bundle) {
- switch (id) {
- case R.id.dialog_import_export_options: {
- return createOptionsDialog();
- }
- case R.string.import_from_sim:
- case R.string.import_from_sdcard: {
- return AccountSelectionUtil.getSelectAccountDialog(mContext, id);
- }
- case R.id.dialog_sdcard_not_found: {
- return new AlertDialog.Builder(mContext)
- .setTitle(R.string.no_sdcard_title)
- .setIconAttribute(android.R.attr.alertDialogIcon)
- .setMessage(R.string.no_sdcard_message)
- .setPositiveButton(android.R.string.ok, null).create();
- }
- }
-
- return null;
- }
-
- private Dialog createOptionsDialog() {
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
// Wrap our context to inflate list items using the correct theme
- final Resources res = mContext.getResources();
- final LayoutInflater dialogInflater = (LayoutInflater)mContext
+ final Resources res = getActivity().getResources();
+ final LayoutInflater dialogInflater = (LayoutInflater)getActivity()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// Adapter that shows a list of string resources
- final ArrayAdapter<Integer> adapter = new ArrayAdapter<Integer>(mContext,
+ final ArrayAdapter<Integer> adapter = new ArrayAdapter<Integer>(getActivity(),
android.R.layout.select_dialog_item) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- if (convertView == null) {
- convertView = dialogInflater.inflate(android.R.layout.select_dialog_item,
- parent, false);
- }
+ final TextView result = (TextView)(convertView != null ? convertView :
+ dialogInflater.inflate(android.R.layout.select_dialog_item, parent, false));
- final int resId = this.getItem(position);
- ((TextView)convertView).setText(resId);
- return convertView;
+ final int resId = getItem(position);
+ result.setText(resId);
+ return result;
}
};
@@ -128,6 +98,7 @@
final DialogInterface.OnClickListener clickListener =
new DialogInterface.OnClickListener() {
+ @Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
@@ -139,8 +110,8 @@
break;
}
case R.string.export_to_sdcard: {
- Intent exportIntent = new Intent(mContext, ExportVCardActivity.class);
- mContext.startActivity(exportIntent);
+ Intent exportIntent = new Intent(getActivity(), ExportVCardActivity.class);
+ getActivity().startActivity(exportIntent);
break;
}
case R.string.share_visible_contacts: {
@@ -148,14 +119,13 @@
break;
}
default: {
- Log.e(TAG, "Unexpected resource: " +
- mContext.getResources().getResourceEntryName(resId));
+ Log.e(TAG, "Unexpected resource: "
+ + getActivity().getResources().getResourceEntryName(resId));
}
}
}
};
-
- return new AlertDialog.Builder(mContext)
+ return new AlertDialog.Builder(getActivity())
.setTitle(R.string.dialog_import_export)
.setNegativeButton(android.R.string.cancel, null)
.setSingleChoiceItems(adapter, -1, clickListener)
@@ -163,13 +133,12 @@
}
private void doShareVisibleContacts() {
-
- // TODO move the query into a loader
- final Cursor cursor = mContext.getContentResolver().query(Contacts.CONTENT_URI,
+ // TODO move the query into a loader and do this in a background thread
+ final Cursor cursor = getActivity().getContentResolver().query(Contacts.CONTENT_URI,
LOOKUP_PROJECTION, Contacts.IN_VISIBLE_GROUP + "!=0", null, null);
try {
if (!cursor.moveToFirst()) {
- Toast.makeText(mContext, R.string.share_error, Toast.LENGTH_SHORT).show();
+ Toast.makeText(getActivity(), R.string.share_error, Toast.LENGTH_SHORT).show();
return;
}
@@ -188,7 +157,7 @@
final Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType(Contacts.CONTENT_VCARD_TYPE);
intent.putExtra(Intent.EXTRA_STREAM, uri);
- mContext.startActivity(intent);
+ getActivity().startActivity(intent);
} finally {
cursor.close();
}
@@ -199,19 +168,37 @@
// - 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(mContext);
+ final AccountTypeManager accountTypes = AccountTypeManager.getInstance(getActivity());
final List<Account> accountList = accountTypes.getAccounts(true);
final int size = accountList.size();
if (size > 1) {
- showDialog(resId, null);
+ // Send over to the account selector
+ ImportExportAccountSelectorDialog.show(getFragmentManager(), resId);
return;
}
- AccountSelectionUtil.doImport(mContext, resId, (size == 1 ? accountList.get(0) : null));
+ AccountSelectionUtil.doImport(getActivity(), resId,
+ (size == 1 ? accountList.get(0) : null));
}
- /* Visible for testing */
- void showDialog(int dialogId, Bundle bundle) {
- ((Activity)mContext).showDialog(dialogId, bundle);
+ /** Sub-Dialog for showing an account selector in case there are several accounts */
+ public static class ImportExportAccountSelectorDialog extends SelectAccountDialogFragment {
+ private static final String SELECTOR_TAG = "ImportExportAccountSelectorDialog";
+ private static final String BUNDLE_RES_ID = "resourceId";
+
+ public static void show(FragmentManager manager, int resId) {
+ final ImportExportAccountSelectorDialog dialog =
+ new ImportExportAccountSelectorDialog();
+ final Bundle bundle = new Bundle();
+ bundle.putInt(BUNDLE_RES_ID, resId);
+ dialog.setArguments(bundle);
+ dialog.show(manager, SELECTOR_TAG);
+ }
+
+ @Override
+ protected void onAccountSelected(Account account) {
+ final int resourceId = getArguments().getInt(BUNDLE_RES_ID);
+ AccountSelectionUtil.doImport(getActivity(), resourceId, account);
+ }
}
}
diff --git a/src/com/android/contacts/interactions/PhoneNumberInteraction.java b/src/com/android/contacts/interactions/PhoneNumberInteraction.java
index 277fa56..399b0ea 100644
--- a/src/com/android/contacts/interactions/PhoneNumberInteraction.java
+++ b/src/com/android/contacts/interactions/PhoneNumberInteraction.java
@@ -16,14 +16,19 @@
package com.android.contacts.interactions;
+import com.google.i18n.phonenumbers.NumberParseException;
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import com.google.i18n.phonenumbers.PhoneNumberUtil.MatchType;
+import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
+
import com.android.contacts.Collapser;
import com.android.contacts.Collapser.Collapsible;
import com.android.contacts.ContactSaveService;
import com.android.contacts.R;
import com.android.contacts.model.AccountType;
-import com.android.contacts.model.AccountType.DataKind;
import com.android.contacts.model.AccountType.StringInflater;
import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.DataKind;
import android.app.Activity;
import android.app.AlertDialog;
@@ -46,7 +51,7 @@
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
-import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -112,8 +117,16 @@
}
public boolean shouldCollapseWith(PhoneItem phoneItem) {
- if (PhoneNumberUtils.compareStrictly(phoneNumber, phoneItem.phoneNumber)) {
- return true;
+ try {
+ PhoneNumberUtil util = PhoneNumberUtil.getInstance();
+ PhoneNumber phoneNumber1 = util.parse(phoneNumber, "ZZ" /* Unknown */);
+ PhoneNumber phoneNumber2 = util.parse(phoneItem.phoneNumber, "ZZ" /* Unknown */);
+ MatchType matchType = util.isNumberMatch(phoneNumber1, phoneNumber2);
+ if (matchType == MatchType.SHORT_NSN_MATCH) {
+ return true;
+ }
+ } catch (NumberParseException e) {
+ return TextUtils.equals(phoneNumber, phoneItem.phoneNumber);
}
return false;
}
diff --git a/src/com/android/contacts/list/ContactBrowseListFragment.java b/src/com/android/contacts/list/ContactBrowseListFragment.java
index 9b99639..1ecfff1 100644
--- a/src/com/android/contacts/list/ContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/ContactBrowseListFragment.java
@@ -520,12 +520,18 @@
protected void selectDefaultContact() {
Uri contactUri = null;
+ ContactListAdapter adapter = getAdapter();
if (mLastSelectedPosition != -1) {
- contactUri = getAdapter().getContactUri(mLastSelectedPosition);
+ int count = adapter.getCount();
+ int pos = mLastSelectedPosition;
+ if (pos >= count && count > 0) {
+ pos = count - 1;
+ }
+ contactUri = adapter.getContactUri(pos);
}
if (contactUri == null) {
- contactUri = getAdapter().getFirstContactUri();
+ contactUri = adapter.getFirstContactUri();
}
setSelectedContactUri(contactUri, false, mSmoothScrollRequested, false, false);
@@ -577,7 +583,7 @@
public void viewContact(Uri contactUri) {
setSelectedContactUri(contactUri, false, false, true, false);
- if (mListener != null) { mListener.onViewContactAction(contactUri); }
+ if (mListener != null) mListener.onViewContactAction(contactUri);
}
public void editContact(Uri contactUri) {
diff --git a/src/com/android/contacts/list/ContactEntryListAdapter.java b/src/com/android/contacts/list/ContactEntryListAdapter.java
index 44e09b0..a2b264b 100644
--- a/src/com/android/contacts/list/ContactEntryListAdapter.java
+++ b/src/com/android/contacts/list/ContactEntryListAdapter.java
@@ -15,6 +15,7 @@
*/
package com.android.contacts.list;
+import com.android.contacts.ContactPhotoManager;
import com.android.contacts.R;
import com.android.contacts.widget.IndexerListAdapter;
import com.android.contacts.widget.TextWithHighlightingFactory;
@@ -61,7 +62,7 @@
private boolean mDisplayPhotos;
private boolean mQuickContactEnabled;
- private ContactPhotoLoader mPhotoLoader;
+ private ContactPhotoManager mPhotoLoader;
private String mQueryString;
private char[] mUpperCaseQueryString;
@@ -225,11 +226,11 @@
return mTextWithHighlightingFactory;
}
- public void setPhotoLoader(ContactPhotoLoader photoLoader) {
+ public void setPhotoLoader(ContactPhotoManager photoLoader) {
mPhotoLoader = photoLoader;
}
- protected ContactPhotoLoader getPhotoLoader() {
+ protected ContactPhotoManager getPhotoLoader() {
return mPhotoLoader;
}
diff --git a/src/com/android/contacts/list/ContactEntryListFragment.java b/src/com/android/contacts/list/ContactEntryListFragment.java
index 70eb0db..fcced62 100644
--- a/src/com/android/contacts/list/ContactEntryListFragment.java
+++ b/src/com/android/contacts/list/ContactEntryListFragment.java
@@ -18,6 +18,7 @@
import com.android.common.widget.CompositeCursorAdapter.Partition;
import com.android.contacts.ContactListEmptyView;
+import com.android.contacts.ContactPhotoManager;
import com.android.contacts.ContactsSearchManager;
import com.android.contacts.R;
import com.android.contacts.preference.ContactsPreferences;
@@ -124,7 +125,7 @@
private int mDirectoryResultLimit = DEFAULT_DIRECTORY_RESULT_LIMIT;
private ContextMenuAdapter mContextMenuAdapter;
- private ContactPhotoLoader mPhotoLoader;
+ private ContactPhotoManager mPhotoManager;
private ContactListEmptyView mEmptyView;
private ProviderStatusLoader mProviderStatusLoader;
private ContactsPreferences mContactsPrefs;
@@ -544,6 +545,7 @@
if (mVerticalScrollbarPosition == View.SCROLLBAR_POSITION_LEFT) {
leftPadding = mContext.getResources().getDimensionPixelOffset(
R.dimen.list_visible_scrollbar_padding);
+ mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY);
} else if (hasScrollbar){
rightPadding = mContext.getResources().getDimensionPixelOffset(
R.dimen.list_visible_scrollbar_padding);
@@ -711,7 +713,7 @@
boolean searchMode = isSearchMode();
mAdapter.setSearchMode(searchMode);
mAdapter.configureDefaultPartition(false, searchMode);
- mAdapter.setPhotoLoader(mPhotoLoader);
+ mAdapter.setPhotoLoader(mPhotoManager);
mListView.setAdapter(mAdapter);
if (!isSearchMode()) {
@@ -762,14 +764,14 @@
protected void configurePhotoLoader() {
if (isPhotoLoaderEnabled() && mContext != null) {
- if (mPhotoLoader == null) {
- mPhotoLoader = new ContactPhotoLoader(mContext, R.drawable.ic_contact_picture);
+ if (mPhotoManager == null) {
+ mPhotoManager = ContactPhotoManager.getInstance(mContext);
}
if (mListView != null) {
mListView.setOnScrollListener(this);
}
if (mAdapter != null) {
- mAdapter.setPhotoLoader(mPhotoLoader);
+ mAdapter.setPhotoLoader(mPhotoManager);
}
}
}
@@ -813,29 +815,13 @@
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == OnScrollListener.SCROLL_STATE_FLING) {
- mPhotoLoader.pause();
+ mPhotoManager.pause();
} else if (isPhotoLoaderEnabled()) {
- mPhotoLoader.resume();
+ mPhotoManager.resume();
}
}
@Override
- public void onResume() {
- super.onResume();
-
- if (isPhotoLoaderEnabled()) {
- mPhotoLoader.resume();
- }
- }
-
- @Override
- public void onDestroy() {
- if (isPhotoLoaderEnabled()) {
- mPhotoLoader.stop();
- }
- super.onDestroy();
- }
-
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
hideSoftKeyboard();
@@ -855,6 +841,7 @@
/**
* Dismisses the soft keyboard when the list takes focus.
*/
+ @Override
public void onFocusChange(View view, boolean hasFocus) {
if (view == mListView && hasFocus) {
hideSoftKeyboard();
@@ -864,6 +851,7 @@
/**
* Dismisses the soft keyboard when the list is touched.
*/
+ @Override
public boolean onTouch(View view, MotionEvent event) {
if (view == mListView) {
hideSoftKeyboard();
diff --git a/src/com/android/contacts/list/ContactListAdapter.java b/src/com/android/contacts/list/ContactListAdapter.java
index a6db641..2c57983 100644
--- a/src/com/android/contacts/list/ContactListAdapter.java
+++ b/src/com/android/contacts/list/ContactListAdapter.java
@@ -79,9 +79,7 @@
Contacts.LOOKUP_KEY, // 9
Contacts.PHONETIC_NAME, // 10
Contacts.HAS_PHONE_NUMBER, // 11
- SearchSnippetColumns.SNIPPET_MIMETYPE, // 12
- SearchSnippetColumns.SNIPPET_DATA1, // 13
- SearchSnippetColumns.SNIPPET_DATA4, // 14
+ SearchSnippetColumns.SNIPPET, // 12
};
protected static final int CONTACT_ID_COLUMN_INDEX = 0;
@@ -96,9 +94,7 @@
protected static final int CONTACT_LOOKUP_KEY_COLUMN_INDEX = 9;
protected static final int CONTACT_PHONETIC_NAME_COLUMN_INDEX = 10;
protected static final int CONTACT_HAS_PHONE_COLUMN_INDEX = 11;
- protected static final int CONTACT_SNIPPET_MIMETYPE_COLUMN_INDEX = 12;
- protected static final int CONTACT_SNIPPET_DATA1_COLUMN_INDEX = 13;
- protected static final int CONTACT_SNIPPET_DATA4_COLUMN_INDEX = 14;
+ protected static final int CONTACT_SNIPPET_COLUMN_INDEX = 12;
private CharSequence mUnknownNameText;
private int mDisplayNameColumnIndex;
@@ -278,8 +274,8 @@
}
protected void bindName(final ContactListItemView view, Cursor cursor) {
- view.showDisplayName(cursor, mDisplayNameColumnIndex, isNameHighlightingEnabled(),
- mAlternativeDisplayNameColumnIndex);
+ view.showDisplayName(cursor, mDisplayNameColumnIndex, mAlternativeDisplayNameColumnIndex,
+ isNameHighlightingEnabled(), getContactNameDisplayOrder());
view.showPhoneticName(cursor, CONTACT_PHONETIC_NAME_COLUMN_INDEX);
}
@@ -289,8 +285,7 @@
}
protected void bindSearchSnippet(final ContactListItemView view, Cursor cursor) {
- view.showSnippet(cursor, CONTACT_SNIPPET_MIMETYPE_COLUMN_INDEX,
- CONTACT_SNIPPET_DATA1_COLUMN_INDEX, CONTACT_SNIPPET_DATA4_COLUMN_INDEX);
+ view.showSnippet(cursor, CONTACT_SNIPPET_COLUMN_INDEX);
}
public int getSelectedContactPosition() {
diff --git a/src/com/android/contacts/list/ContactListItemView.java b/src/com/android/contacts/list/ContactListItemView.java
index c943534..022c2f6 100644
--- a/src/com/android/contacts/list/ContactListItemView.java
+++ b/src/com/android/contacts/list/ContactListItemView.java
@@ -18,6 +18,7 @@
import com.android.contacts.ContactPresenceIconUtil;
import com.android.contacts.R;
+import com.android.contacts.format.FormatUtils;
import com.android.contacts.widget.TextWithHighlighting;
import com.android.contacts.widget.TextWithHighlightingFactory;
@@ -30,12 +31,11 @@
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Nickname;
-import android.provider.ContactsContract.CommonDataKinds.Organization;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
+import android.text.Spannable;
import android.text.SpannableString;
+import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.text.style.ForegroundColorSpan;
@@ -49,6 +49,8 @@
import android.widget.QuickContactBadge;
import android.widget.TextView;
+import java.util.Arrays;
+
/**
* A custom view for an item in the contact list.
*/
@@ -809,9 +811,21 @@
return mActivatedStateSupported ? TruncateAt.START : TruncateAt.MARQUEE;
}
- public void showDisplayName(Cursor cursor, int nameColumnIndex, boolean highlightingEnabled,
- int alternativeNameColumnIndex) {
+ public void showDisplayName(Cursor cursor, int nameColumnIndex, int alternativeNameColumnIndex,
+ boolean highlightingEnabled, int displayOrder) {
+
+ // Copy out the display name and alternate display name, and compute the point at which
+ // the two overlap (for bolding).
cursor.copyStringToBuffer(nameColumnIndex, mNameBuffer);
+ cursor.copyStringToBuffer(alternativeNameColumnIndex, mHighlightedTextBuffer);
+ int overlapPoint = FormatUtils.overlapPoint(mNameBuffer, mHighlightedTextBuffer);
+ int boldStart = 0;
+ int boldEnd = overlapPoint;
+ if (displayOrder == ContactsContract.Preferences.DISPLAY_ORDER_ALTERNATIVE) {
+ boldStart = overlapPoint;
+ boldEnd = mNameBuffer.sizeCopied;
+ }
+
TextView nameView = getNameTextView();
int size = mNameBuffer.sizeCopied;
if (size != 0) {
@@ -822,11 +836,24 @@
mTextWithHighlighting =
mTextWithHighlightingFactory.createTextWithHighlighting();
}
- cursor.copyStringToBuffer(alternativeNameColumnIndex, mHighlightedTextBuffer);
mTextWithHighlighting.setText(mNameBuffer, mHighlightedTextBuffer);
- nameView.setText(mTextWithHighlighting);
+ if (overlapPoint > 0) {
+ // Bold the first name.
+ nameView.setText(FormatUtils.applyStyleToSpan(Typeface.BOLD,
+ mTextWithHighlighting, boldStart, boldEnd,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE));
+ } else {
+ nameView.setText(mTextWithHighlighting);
+ }
} else {
- nameView.setText(mNameBuffer.data, 0, size);
+ if (overlapPoint > 0) {
+ // Bold the first name.
+ nameView.setText(FormatUtils.applyStyleToSpan(Typeface.BOLD,
+ new String(Arrays.copyOfRange(mNameBuffer.data, 0, size)),
+ boldStart, boldEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE));
+ } else {
+ nameView.setText(mNameBuffer.data, 0, size);
+ }
}
} else {
nameView.setText(mUnknownNameText);
@@ -863,36 +890,43 @@
/**
* Shows search snippet.
*/
- public void showSnippet(Cursor cursor, int summarySnippetMimetypeColumnIndex,
- int summarySnippetData1ColumnIndex, int summarySnippetData4ColumnIndex) {
- if (cursor.getColumnCount() <= summarySnippetMimetypeColumnIndex) {
+ public void showSnippet(Cursor cursor, int summarySnippetColumnIndex) {
+ if (cursor.getColumnCount() <= summarySnippetColumnIndex) {
setSnippet(null);
return;
}
- String snippet = null;
- String snippetMimeType = cursor.getString(summarySnippetMimetypeColumnIndex);
- if (Email.CONTENT_ITEM_TYPE.equals(snippetMimeType)
- || Nickname.CONTENT_ITEM_TYPE.equals(snippetMimeType)
- || Phone.CONTENT_ITEM_TYPE.equals(snippetMimeType)) {
- String value = cursor.getString(summarySnippetData1ColumnIndex);
- if (!TextUtils.isEmpty(value)) {
- snippet = value;
- }
- } else if (Organization.CONTENT_ITEM_TYPE.equals(snippetMimeType)) {
- String company = cursor.getString(summarySnippetData1ColumnIndex);
- String title = cursor.getString(summarySnippetData4ColumnIndex);
- if (!TextUtils.isEmpty(company)) {
- if (!TextUtils.isEmpty(title)) {
- snippet = company + " / " + title;
- } else {
- snippet = company;
+ String snippet = cursor.getString(summarySnippetColumnIndex);
+ 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;
}
- } else if (!TextUtils.isEmpty(title)) {
- snippet = title;
+ 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);
}
@@ -931,7 +965,9 @@
}
String string = new String(text.data, 0, text.sizeCopied);
- SpannableString name = new SpannableString(string);
+ SpannableString name = new SpannableString(
+ FormatUtils.applyStyleToSpan(Typeface.BOLD, string, 0, index,
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE));
name.setSpan(mPrefixColorSpan, index, index + mHighlightedPrefix.length, 0 /* flags */);
textView.setText(name);
} else {
diff --git a/src/com/android/contacts/list/ContactPhotoLoader.java b/src/com/android/contacts/list/ContactPhotoLoader.java
deleted file mode 100644
index a6f40b6..0000000
--- a/src/com/android/contacts/list/ContactPhotoLoader.java
+++ /dev/null
@@ -1,515 +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.list;
-
-import com.google.android.collect.Lists;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Handler.Callback;
-import android.os.HandlerThread;
-import android.os.Message;
-import android.provider.ContactsContract.Contacts.Photo;
-import android.provider.ContactsContract.Data;
-import android.util.Log;
-import android.widget.ImageView;
-
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.lang.ref.SoftReference;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Asynchronously loads contact photos and maintains cache of photos. The class is
- * mostly single-threaded. The only two methods accessed by the loader thread are
- * {@link #cacheBitmap} and {@link #obtainPhotoIdsAndUrisToLoad}. Those methods access concurrent
- * hash maps shared with the main thread.
- */
-public class ContactPhotoLoader implements Callback {
- private static final String TAG = "ContactPhotoLoader";
- private static final String LOADER_THREAD_NAME = "ContactPhotoLoader";
-
- /**
- * 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 final String[] COLUMNS = new String[] { Photo._ID, Photo.PHOTO };
-
- /**
- * The resource ID of the image to be used when the photo is unavailable or being
- * loaded.
- */
- private final int mDefaultResourceId;
-
- /**
- * Maintains the state of a particular photo.
- */
- private static class BitmapHolder {
- private static final int NEEDED = 0;
- private static final int LOADING = 1;
- private static final int LOADED = 2;
- private static final int LOADED_NEEDS_RELOAD = 3;
-
- int state;
- Bitmap bitmap;
- SoftReference<Bitmap> bitmapRef;
- }
-
- /**
- * A soft cache for photos.
- */
- private final ConcurrentHashMap<Object, BitmapHolder> mBitmapCache =
- new ConcurrentHashMap<Object, BitmapHolder>();
-
- /**
- * A map from ImageView to the corresponding photo ID. Please note that this
- * photo ID may change before the photo loading request is started.
- */
- private final ConcurrentHashMap<ImageView, Object> mPendingRequests =
- new ConcurrentHashMap<ImageView, Object>();
-
- /**
- * 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;
-
- private final Context mContext;
-
- /**
- * Constructor.
- *
- * @param context content context
- * @param defaultResourceId the image resource ID to be used when there is
- * no photo for a contact
- */
- public ContactPhotoLoader(Context context, int defaultResourceId) {
- mDefaultResourceId = defaultResourceId;
- mContext = context;
- }
-
- /**
- * 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 database.
- */
- public void loadPhoto(ImageView view, long photoId) {
- if (photoId == 0) {
- // No photo is needed
- view.setImageResource(mDefaultResourceId);
- mPendingRequests.remove(view);
- } else {
- loadPhotoByIdOrUri(view, photoId);
- }
- }
-
- /**
- * 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.
- */
- public void loadPhoto(ImageView view, Uri photoUri) {
- if (photoUri == null) {
- // No photo is needed
- view.setImageResource(mDefaultResourceId);
- mPendingRequests.remove(view);
- } else {
- loadPhotoByIdOrUri(view, photoUri);
- }
- }
-
- private void loadPhotoByIdOrUri(ImageView view, Object key) {
- boolean loaded = loadCachedPhoto(view, key);
- if (loaded) {
- mPendingRequests.remove(view);
- } else {
- mPendingRequests.put(view, key);
- if (!mPaused) {
- // Send a request to start loading photos
- requestLoading();
- }
- }
- }
-
- /**
- * Mark 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 void refreshCache() {
- for (BitmapHolder holder : mBitmapCache.values()) {
- if (holder.state == BitmapHolder.LOADED) {
- holder.state = BitmapHolder.LOADED_NEEDS_RELOAD;
- }
- }
- }
-
- /**
- * Checks if the photo is present in cache. If so, sets the photo on the view,
- * otherwise sets the state of the photo to {@link BitmapHolder#NEEDED} and
- * temporarily set the image to the default resource ID.
- */
- private boolean loadCachedPhoto(ImageView view, Object key) {
- BitmapHolder holder = mBitmapCache.get(key);
- if (holder == null) {
- holder = new BitmapHolder();
- mBitmapCache.put(key, holder);
- } else {
- boolean loaded = (holder.state == BitmapHolder.LOADED);
- boolean loadedNeedsReload = (holder.state == BitmapHolder.LOADED_NEEDS_RELOAD);
- if (loadedNeedsReload) {
- holder.state = BitmapHolder.NEEDED;
- }
-
- // Null bitmap reference means that database contains no bytes for the photo
- if ((loaded || loadedNeedsReload) && holder.bitmapRef == null) {
- view.setImageResource(mDefaultResourceId);
- return loaded;
- }
-
- if (holder.bitmapRef != null) {
- Bitmap bitmap = holder.bitmapRef.get();
- if (bitmap != null) {
- view.setImageBitmap(bitmap);
- return loaded;
- }
-
- // Null bitmap means that the soft reference was released by the GC
- // and we need to reload the photo.
- holder.bitmapRef = null;
- }
- }
-
- // The bitmap has not been loaded - should display the placeholder image.
- view.setImageResource(mDefaultResourceId);
- holder.state = BitmapHolder.NEEDED;
- return false;
- }
-
- /**
- * Stops loading images, kills the image loader thread and clears all caches.
- */
- public void stop() {
- pause();
-
- if (mLoaderThread != null) {
- mLoaderThread.quit();
- mLoaderThread = null;
- }
-
- mPendingRequests.clear();
- mBitmapCache.clear();
- }
-
- public void clear() {
- mPendingRequests.clear();
- mBitmapCache.clear();
- }
-
- /**
- * Temporarily stops loading photos from the database.
- */
- public void pause() {
- mPaused = true;
- }
-
- /**
- * Resumes loading photos from the database.
- */
- public void resume() {
- mPaused = false;
- 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.
- */
- public boolean handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_REQUEST_LOADING: {
- mLoadingRequested = false;
- if (!mPaused) {
- if (mLoaderThread == null) {
- mLoaderThread = new LoaderThread(mContext.getContentResolver());
- mLoaderThread.start();
- }
-
- mLoaderThread.requestLoading();
- }
- return true;
- }
-
- case MESSAGE_PHOTOS_LOADED: {
- if (!mPaused) {
- processLoadedImages();
- }
- return true;
- }
- }
- return false;
- }
-
- /**
- * 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() {
- Iterator<ImageView> iterator = mPendingRequests.keySet().iterator();
- while (iterator.hasNext()) {
- ImageView view = iterator.next();
- Object key = mPendingRequests.get(view);
- boolean loaded = loadCachedPhoto(view, key);
- if (loaded) {
- iterator.remove();
- }
- }
-
- softenCache();
-
- if (!mPendingRequests.isEmpty()) {
- requestLoading();
- }
- }
-
- /**
- * Removes strong references to loaded bitmaps to allow them to be garbage collected
- * if needed.
- */
- private void softenCache() {
- for (BitmapHolder holder : mBitmapCache.values()) {
- holder.bitmap = null;
- }
- }
-
- /**
- * Stores the supplied bitmap in cache.
- */
- private void cacheBitmap(Object key, byte[] bytes) {
- if (mPaused) {
- return;
- }
-
- BitmapHolder holder = new BitmapHolder();
- holder.state = BitmapHolder.LOADED;
- if (bytes != null) {
- try {
- Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, null);
- holder.bitmap = bitmap;
- holder.bitmapRef = new SoftReference<Bitmap>(bitmap);
- } catch (OutOfMemoryError e) {
- // Do nothing - the photo will appear to be missing
- }
- }
- mBitmapCache.put(key, holder);
- }
-
- /**
- * Populates an array of photo IDs that need to be loaded.
- */
- private void obtainPhotoIdsAndUrisToLoad(ArrayList<Long> photoIds,
- ArrayList<String> photoIdsAsStrings, ArrayList<Uri> uris) {
- photoIds.clear();
- photoIdsAsStrings.clear();
- uris.clear();
-
- /*
- * 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<Object> iterator = mPendingRequests.values().iterator();
- while (iterator.hasNext()) {
- Object key = iterator.next();
- BitmapHolder holder = mBitmapCache.get(key);
- if (holder != null && holder.state == BitmapHolder.NEEDED) {
- // Assuming atomic behavior
- holder.state = BitmapHolder.LOADING;
- if (key instanceof Long) {
- photoIds.add((Long)key);
- photoIdsAsStrings.add(key.toString());
- } else {
- uris.add((Uri)key);
- }
- }
- }
- }
-
- /**
- * 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 final ContentResolver mResolver;
- private final StringBuilder mStringBuilder = new StringBuilder();
- private final ArrayList<Long> mPhotoIds = Lists.newArrayList();
- private final ArrayList<String> mPhotoIdsAsStrings = Lists.newArrayList();
- private final ArrayList<Uri> mPhotoUris = Lists.newArrayList();
- private Handler mLoaderThreadHandler;
- private byte mBuffer[];
-
- public LoaderThread(ContentResolver resolver) {
- super(LOADER_THREAD_NAME);
- mResolver = resolver;
- }
-
- /**
- * Sends a message to this thread to load requested photos.
- */
- public void requestLoading() {
- if (mLoaderThreadHandler == null) {
- mLoaderThreadHandler = new Handler(getLooper(), this);
- }
- mLoaderThreadHandler.sendEmptyMessage(0);
- }
-
- /**
- * Receives the above message, loads photos and then sends a message
- * to the main thread to process them.
- */
- public boolean handleMessage(Message msg) {
- loadPhotosFromDatabase();
- return true;
- }
-
- private void loadPhotosFromDatabase() {
- obtainPhotoIdsAndUrisToLoad(mPhotoIds, mPhotoIdsAsStrings, mPhotoUris);
-
- int count = mPhotoIds.size();
- if (count != 0) {
- mStringBuilder.setLength(0);
- mStringBuilder.append(Photo._ID + " IN(");
- for (int i = 0; i < count; i++) {
- if (i != 0) {
- mStringBuilder.append(',');
- }
- mStringBuilder.append('?');
- }
- mStringBuilder.append(')');
-
- Cursor cursor = null;
- try {
- 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);
- mPhotoIds.remove(id);
- }
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
-
- // Remaining photos were not found in the database - mark the cache accordingly.
- count = mPhotoIds.size();
- for (int i = 0; i < count; i++) {
- cacheBitmap(mPhotoIds.get(i), null);
- }
- mMainThreadHandler.sendEmptyMessage(MESSAGE_PHOTOS_LOADED);
- }
-
- count = mPhotoUris.size();
- for (int i = 0; i < count; i++) {
- Uri uri = mPhotoUris.get(i);
- if (mBuffer == null) {
- mBuffer = new byte[BUFFER_SIZE];
- }
- try {
- InputStream 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(uri, baos.toByteArray());
- mMainThreadHandler.sendEmptyMessage(MESSAGE_PHOTOS_LOADED);
- } else {
- Log.v(TAG, "Cannot load photo " + uri);
- cacheBitmap(uri, null);
- }
- } catch (Exception ex) {
- Log.v(TAG, "Cannot load photo " + uri, ex);
- cacheBitmap(uri, null);
- }
- }
- }
- }
-}
diff --git a/src/com/android/contacts/list/ContactsIntentResolver.java b/src/com/android/contacts/list/ContactsIntentResolver.java
index afe29df..3ef68d8 100644
--- a/src/com/android/contacts/list/ContactsIntentResolver.java
+++ b/src/com/android/contacts/list/ContactsIntentResolver.java
@@ -27,6 +27,7 @@
import android.provider.Contacts.ContactMethods;
import android.provider.Contacts.People;
import android.provider.Contacts.Phones;
+import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.Contacts;
@@ -95,6 +96,8 @@
} else if (ContactMethods.CONTENT_POSTAL_TYPE.equals(resolvedType)) {
request.setActionCode(ContactsRequest.ACTION_PICK_POSTAL);
request.setLegacyCompatibilityMode(true);
+ } else if (Email.CONTENT_TYPE.equals(resolvedType)) {
+ request.setActionCode(ContactsRequest.ACTION_PICK_EMAIL);
}
} else if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) {
String component = intent.getComponent().getClassName();
diff --git a/src/com/android/contacts/list/ContactsRequest.java b/src/com/android/contacts/list/ContactsRequest.java
index aefa451..e20d189 100644
--- a/src/com/android/contacts/list/ContactsRequest.java
+++ b/src/com/android/contacts/list/ContactsRequest.java
@@ -62,6 +62,9 @@
/** Show all postal addresses and pick them when clicking */
public static final int ACTION_PICK_POSTAL = 100;
+ /** Show all postal addresses and pick them when clicking */
+ public static final int ACTION_PICK_EMAIL = 105;
+
/** Show all contacts and create a shortcut for the picked contact */
public static final int ACTION_CREATE_SHORTCUT_CONTACT = 110;
diff --git a/src/com/android/contacts/list/CustomContactListFilterActivity.java b/src/com/android/contacts/list/CustomContactListFilterActivity.java
index 0f3fafd..dae7233 100644
--- a/src/com/android/contacts/list/CustomContactListFilterActivity.java
+++ b/src/com/android/contacts/list/CustomContactListFilterActivity.java
@@ -26,6 +26,7 @@
import com.android.contacts.preference.ContactsPreferences;
import com.android.contacts.util.EmptyService;
import com.android.contacts.util.LocalizedNameResolver;
+import com.android.contacts.util.PhoneCapabilityTester;
import com.android.contacts.util.WeakAsyncTask;
import com.google.android.collect.Lists;
@@ -113,8 +114,10 @@
createWithPhonesOnlyPreferenceView(inflater);
createDisplayGroupHeader(inflater);
- mList.addHeaderView(mHeaderPhones, null, true);
- mList.addHeaderView(mHeaderSeparator, null, false);
+ if (mHeaderPhones != null) {
+ mList.addHeaderView(mHeaderPhones, null, true);
+ mList.addHeaderView(mHeaderSeparator, null, false);
+ }
findViewById(R.id.btn_done).setOnClickListener(this);
findViewById(R.id.btn_discard).setOnClickListener(this);
@@ -127,12 +130,18 @@
}
private void createWithPhonesOnlyPreferenceView(LayoutInflater inflater) {
+ boolean optionSelected = mPrefs.getBoolean(ContactsPreferences.PREF_DISPLAY_ONLY_PHONES,
+ ContactsPreferences.PREF_DISPLAY_ONLY_PHONES_DEFAULT);
+
+ if (!optionSelected && !PhoneCapabilityTester.isPhone(this)) {
+ return;
+ }
+
// Add the "Only contacts with phones" header modifier.
mHeaderPhones = inflater.inflate(R.layout.contact_list_filter_phones_only, mList, false);
mHeaderPhones.setId(R.id.header_phones);
mDisplayPhones = (CheckBox) mHeaderPhones.findViewById(android.R.id.checkbox);
- mDisplayPhones.setChecked(mPrefs.getBoolean(ContactsPreferences.PREF_DISPLAY_ONLY_PHONES,
- ContactsPreferences.PREF_DISPLAY_ONLY_PHONES_DEFAULT));
+ mDisplayPhones.setChecked(optionSelected);
final TextView text1 = (TextView) mHeaderPhones.findViewById(android.R.id.text1);
text1.setText(R.string.showFilterPhones);
final TextView text2 = (TextView) mHeaderPhones.findViewById(android.R.id.text2);
@@ -871,7 +880,10 @@
return;
}
- setDisplayOnlyPhones(mDisplayPhones.isChecked());
+ if (mDisplayPhones != null) {
+ setDisplayOnlyPhones(mDisplayPhones.isChecked());
+ }
+
setResult(RESULT_OK);
final ArrayList<ContentProviderOperation> diff = mAdapter.mAccounts.buildDiff();
diff --git a/src/com/android/contacts/list/DefaultContactListAdapter.java b/src/com/android/contacts/list/DefaultContactListAdapter.java
index 164a2cd..3e8c6f1 100644
--- a/src/com/android/contacts/list/DefaultContactListAdapter.java
+++ b/src/com/android/contacts/list/DefaultContactListAdapter.java
@@ -31,6 +31,7 @@
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.Directory;
import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.SearchSnippetColumns;
import android.text.TextUtils;
import android.view.View;
@@ -42,6 +43,14 @@
*/
public class DefaultContactListAdapter extends ContactListAdapter {
+ public static final char SNIPPET_START_MATCH = '\u0001';
+ public static final char SNIPPET_END_MATCH = '\u0001';
+ public static final String SNIPPET_ELLIPSIS = "\u2026";
+ public static final int SNIPPET_MAX_TOKENS = 5;
+
+ public static final String SNIPPET_ARGS = SNIPPET_START_MATCH + "," + SNIPPET_END_MATCH + ","
+ + SNIPPET_ELLIPSIS + "," + SNIPPET_MAX_TOKENS;
+
public DefaultContactListAdapter(Context context) {
super(context);
}
@@ -71,6 +80,8 @@
builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
String.valueOf(getDirectoryResultLimit()));
}
+ builder.appendQueryParameter(SearchSnippetColumns.SNIPPET_ARGS_PARAM_KEY,
+ SNIPPET_ARGS);
applyDataRestriction(builder);
loader.setUri(builder.build());
loader.setProjection(FILTER_PROJECTION);
diff --git a/src/com/android/contacts/list/EmailAddressListAdapter.java b/src/com/android/contacts/list/EmailAddressListAdapter.java
new file mode 100644
index 0000000..eae02b5
--- /dev/null
+++ b/src/com/android/contacts/list/EmailAddressListAdapter.java
@@ -0,0 +1,190 @@
+/*
+ * 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.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.ContactCounts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A cursor adapter for the {@link Email#CONTENT_TYPE} content type.
+ */
+public class EmailAddressListAdapter extends ContactEntryListAdapter {
+
+ static final String[] EMAILS_PROJECTION = new String[] {
+ Email._ID, // 0
+ Email.TYPE, // 1
+ Email.LABEL, // 2
+ Email.DATA, // 3
+ Email.DISPLAY_NAME_PRIMARY, // 4
+ Email.DISPLAY_NAME_ALTERNATIVE, // 5
+ Email.PHOTO_ID, // 6
+ };
+
+ protected static final int EMAIL_ID_COLUMN_INDEX = 0;
+ protected static final int EMAIL_TYPE_COLUMN_INDEX = 1;
+ protected static final int EMAIL_LABEL_COLUMN_INDEX = 2;
+ protected static final int EMAIL_ADDRESS_COLUMN_INDEX = 3;
+ protected static final int EMAIL_PRIMARY_DISPLAY_NAME_COLUMN_INDEX = 4;
+ protected static final int EMAIL_ALTERNATIVE_DISPLAY_NAME_COLUMN_INDEX = 5;
+ protected static final int EMAIL_PHOTO_ID_COLUMN_INDEX = 6;
+
+ private CharSequence mUnknownNameText;
+ private int mDisplayNameColumnIndex;
+ private int mAlternativeDisplayNameColumnIndex;
+
+ public EmailAddressListAdapter(Context context) {
+ super(context);
+
+ mUnknownNameText = context.getText(android.R.string.unknownName);
+ }
+
+ @Override
+ public void configureLoader(CursorLoader loader, long directoryId) {
+ final Builder builder;
+ if (isSearchMode()) {
+ builder = Email.CONTENT_FILTER_URI.buildUpon();
+ String query = getQueryString();
+ builder.appendPath(TextUtils.isEmpty(query) ? "" : query);
+ } else {
+ builder = Email.CONTENT_URI.buildUpon();
+ }
+ builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(directoryId));
+ applyDataRestriction(builder);
+ loader.setUri(builder.build());
+ loader.setProjection(EMAILS_PROJECTION);
+
+ if (getSortOrder() == ContactsContract.Preferences.SORT_ORDER_PRIMARY) {
+ loader.setSortOrder(Email.SORT_KEY_PRIMARY);
+ } else {
+ loader.setSortOrder(Email.SORT_KEY_ALTERNATIVE);
+ }
+ }
+
+ protected static Builder buildSectionIndexerUri(Uri uri) {
+ return uri.buildUpon()
+ .appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true");
+ }
+
+ @Override
+ public String getContactDisplayName(int position) {
+ return ((Cursor)getItem(position)).getString(mDisplayNameColumnIndex);
+ }
+
+ @Override
+ public void setContactNameDisplayOrder(int displayOrder) {
+ super.setContactNameDisplayOrder(displayOrder);
+ if (getContactNameDisplayOrder() == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) {
+ mDisplayNameColumnIndex = EMAIL_PRIMARY_DISPLAY_NAME_COLUMN_INDEX;
+ mAlternativeDisplayNameColumnIndex = EMAIL_ALTERNATIVE_DISPLAY_NAME_COLUMN_INDEX;
+ } else {
+ mDisplayNameColumnIndex = EMAIL_ALTERNATIVE_DISPLAY_NAME_COLUMN_INDEX;
+ mAlternativeDisplayNameColumnIndex = EMAIL_PRIMARY_DISPLAY_NAME_COLUMN_INDEX;
+ }
+ }
+
+ /**
+ * Builds a {@link Data#CONTENT_URI} for the current cursor
+ * position.
+ */
+ public Uri getDataUri(int position) {
+ long id = ((Cursor)getItem(position)).getLong(EMAIL_ID_COLUMN_INDEX);
+ return ContentUris.withAppendedId(Data.CONTENT_URI, id);
+ }
+
+ @Override
+ protected View newView(Context context, int partition, Cursor cursor, int position,
+ ViewGroup parent) {
+ final ContactListItemView view = new ContactListItemView(context, null);
+ view.setUnknownNameText(mUnknownNameText);
+ view.setTextWithHighlightingFactory(getTextWithHighlightingFactory());
+ view.setQuickContactEnabled(isQuickContactEnabled());
+ return view;
+ }
+
+ @Override
+ protected void bindView(View itemView, int partition, Cursor cursor, int position) {
+ ContactListItemView view = (ContactListItemView)itemView;
+ bindSectionHeaderAndDivider(view, position);
+ bindName(view, cursor);
+ bindPhoto(view, cursor);
+ bindEmailAddress(view, cursor);
+ }
+
+ protected void bindEmailAddress(ContactListItemView view, Cursor cursor) {
+ CharSequence label = null;
+ if (!cursor.isNull(EMAIL_TYPE_COLUMN_INDEX)) {
+ final int type = cursor.getInt(EMAIL_TYPE_COLUMN_INDEX);
+ final String customLabel = cursor.getString(EMAIL_LABEL_COLUMN_INDEX);
+
+ // TODO cache
+ label = Email.getTypeLabel(getContext().getResources(), type, customLabel);
+ }
+ view.setLabel(label);
+ view.showData(cursor, EMAIL_ADDRESS_COLUMN_INDEX);
+ }
+
+ protected void bindSectionHeaderAndDivider(final ContactListItemView view, int position) {
+ final int section = getSectionForPosition(position);
+ if (getPositionForSection(section) == position) {
+ String title = (String)getSections()[section];
+ view.setSectionHeader(title);
+ } else {
+ view.setDividerVisible(false);
+ view.setSectionHeader(null);
+ }
+
+ // move the divider for the last item in a section
+ if (getPositionForSection(section + 1) - 1 == position) {
+ view.setDividerVisible(false);
+ } else {
+ view.setDividerVisible(true);
+ }
+ }
+
+ protected void bindName(final ContactListItemView view, Cursor cursor) {
+ view.showDisplayName(cursor, mDisplayNameColumnIndex, mAlternativeDisplayNameColumnIndex,
+ isNameHighlightingEnabled(), getContactNameDisplayOrder());
+// view.showPhoneticName(cursor, PHONE_PHONETIC_NAME_COLUMN_INDEX);
+ }
+
+ protected void bindPhoto(final ContactListItemView view, Cursor cursor) {
+ long photoId = 0;
+ if (!cursor.isNull(EMAIL_PHOTO_ID_COLUMN_INDEX)) {
+ photoId = cursor.getLong(EMAIL_PHOTO_ID_COLUMN_INDEX);
+ }
+
+ getPhotoLoader().loadPhoto(view.getPhotoView(), photoId);
+ }
+//
+// protected void bindSearchSnippet(final ContactListItemView view, Cursor cursor) {
+// view.showSnippet(cursor, SUMMARY_SNIPPET_MIMETYPE_COLUMN_INDEX,
+// SUMMARY_SNIPPET_DATA1_COLUMN_INDEX, SUMMARY_SNIPPET_DATA4_COLUMN_INDEX);
+// }
+
+}
diff --git a/src/com/android/contacts/list/EmailAddressPickerFragment.java b/src/com/android/contacts/list/EmailAddressPickerFragment.java
new file mode 100644
index 0000000..168e135
--- /dev/null
+++ b/src/com/android/contacts/list/EmailAddressPickerFragment.java
@@ -0,0 +1,64 @@
+/*
+ * 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.list;
+
+import com.android.contacts.R;
+
+import android.net.Uri;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Fragment containing an email list for picking.
+ */
+public class EmailAddressPickerFragment extends ContactEntryListFragment<ContactEntryListAdapter> {
+ private OnEmailAddressPickerActionListener mListener;
+
+ public EmailAddressPickerFragment() {
+ setQuickContactEnabled(false);
+ setPhotoLoaderEnabled(true);
+ setSectionHeaderDisplayEnabled(true);
+ setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_DATA_SHORTCUT);
+ }
+
+ public void setOnEmailAddressPickerActionListener(OnEmailAddressPickerActionListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ protected void onItemClick(int position, long id) {
+ EmailAddressListAdapter adapter = (EmailAddressListAdapter)getAdapter();
+ pickEmailAddress(adapter.getDataUri(position));
+ }
+
+ @Override
+ protected ContactEntryListAdapter createListAdapter() {
+ EmailAddressListAdapter adapter = new EmailAddressListAdapter(getActivity());
+ adapter.setSectionHeaderDisplayEnabled(true);
+ adapter.setDisplayPhotos(true);
+ return adapter;
+ }
+
+ @Override
+ protected View inflateView(LayoutInflater inflater, ViewGroup container) {
+ return inflater.inflate(R.layout.contacts_list_content, null);
+ }
+
+ private void pickEmailAddress(Uri uri) {
+ mListener.onPickEmailAddressAction(uri);
+ }
+}
diff --git a/src/com/android/contacts/list/LegacyContactListAdapter.java b/src/com/android/contacts/list/LegacyContactListAdapter.java
index 6747d1f..ffc8fc3 100644
--- a/src/com/android/contacts/list/LegacyContactListAdapter.java
+++ b/src/com/android/contacts/list/LegacyContactListAdapter.java
@@ -85,7 +85,8 @@
}
protected void bindName(final ContactListItemView view, Cursor cursor) {
- view.showDisplayName(cursor, PERSON_DISPLAY_NAME_COLUMN_INDEX, false, 0);
+ view.showDisplayName(cursor, PERSON_DISPLAY_NAME_COLUMN_INDEX, 0, false,
+ getContactNameDisplayOrder());
view.showPhoneticName(cursor, PERSON_PHONETIC_NAME_COLUMN_INDEX);
}
diff --git a/src/com/android/contacts/list/LegacyPhoneNumberListAdapter.java b/src/com/android/contacts/list/LegacyPhoneNumberListAdapter.java
index 47747fb..547650d 100644
--- a/src/com/android/contacts/list/LegacyPhoneNumberListAdapter.java
+++ b/src/com/android/contacts/list/LegacyPhoneNumberListAdapter.java
@@ -89,7 +89,8 @@
}
protected void bindName(final ContactListItemView view, Cursor cursor) {
- view.showDisplayName(cursor, PHONE_DISPLAY_NAME_COLUMN_INDEX, false, 0);
+ view.showDisplayName(cursor, PHONE_DISPLAY_NAME_COLUMN_INDEX, 0, false,
+ getContactNameDisplayOrder());
view.showPhoneticName(cursor, PHONE_PHONETIC_NAME_COLUMN_INDEX);
}
diff --git a/src/com/android/contacts/list/LegacyPostalAddressListAdapter.java b/src/com/android/contacts/list/LegacyPostalAddressListAdapter.java
index 3796c62..48b3f0c 100644
--- a/src/com/android/contacts/list/LegacyPostalAddressListAdapter.java
+++ b/src/com/android/contacts/list/LegacyPostalAddressListAdapter.java
@@ -90,7 +90,8 @@
}
protected void bindName(final ContactListItemView view, Cursor cursor) {
- view.showDisplayName(cursor, POSTAL_DISPLAY_NAME_COLUMN_INDEX, false, 0);
+ view.showDisplayName(cursor, POSTAL_DISPLAY_NAME_COLUMN_INDEX, 0, false,
+ getContactNameDisplayOrder());
view.showPhoneticName(cursor, POSTAL_PHONETIC_NAME_COLUMN_INDEX);
}
diff --git a/src/com/android/contacts/list/OnEmailAddressPickerActionListener.java b/src/com/android/contacts/list/OnEmailAddressPickerActionListener.java
new file mode 100644
index 0000000..e785323
--- /dev/null
+++ b/src/com/android/contacts/list/OnEmailAddressPickerActionListener.java
@@ -0,0 +1,29 @@
+/*
+ * 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.list;
+
+import android.net.Uri;
+
+/**
+ * Action callbacks that can be sent by a email address picker.
+ */
+public interface OnEmailAddressPickerActionListener {
+
+ /**
+ * Returns the selected phone number to the requester.
+ */
+ void onPickEmailAddressAction(Uri dataUri);
+}
diff --git a/src/com/android/contacts/list/PhoneNumberListAdapter.java b/src/com/android/contacts/list/PhoneNumberListAdapter.java
index 48a6042..9356bb6 100644
--- a/src/com/android/contacts/list/PhoneNumberListAdapter.java
+++ b/src/com/android/contacts/list/PhoneNumberListAdapter.java
@@ -185,8 +185,8 @@
}
protected void bindName(final ContactListItemView view, Cursor cursor) {
- view.showDisplayName(cursor, mDisplayNameColumnIndex, isNameHighlightingEnabled(),
- mAlternativeDisplayNameColumnIndex);
+ view.showDisplayName(cursor, mDisplayNameColumnIndex, mAlternativeDisplayNameColumnIndex,
+ isNameHighlightingEnabled(), getContactNameDisplayOrder());
view.showPhoneticName(cursor, PHONE_PHONETIC_NAME_COLUMN_INDEX);
}
diff --git a/src/com/android/contacts/list/PostalAddressListAdapter.java b/src/com/android/contacts/list/PostalAddressListAdapter.java
index e622ec6..86d465a 100644
--- a/src/com/android/contacts/list/PostalAddressListAdapter.java
+++ b/src/com/android/contacts/list/PostalAddressListAdapter.java
@@ -131,7 +131,7 @@
final String customLabel = cursor.getString(POSTAL_LABEL_COLUMN_INDEX);
// TODO cache
- label = StructuredPostal.getTypeLabel(getContext().getResources(), type, label);
+ label = StructuredPostal.getTypeLabel(getContext().getResources(), type, customLabel);
}
view.setLabel(label);
view.showData(cursor, POSTAL_ADDRESS_COLUMN_INDEX);
@@ -156,8 +156,8 @@
}
protected void bindName(final ContactListItemView view, Cursor cursor) {
- view.showDisplayName(cursor, mDisplayNameColumnIndex, isNameHighlightingEnabled(),
- mAlternativeDisplayNameColumnIndex);
+ view.showDisplayName(cursor, mDisplayNameColumnIndex, mAlternativeDisplayNameColumnIndex,
+ isNameHighlightingEnabled(), getContactNameDisplayOrder());
// view.showPhoneticName(cursor, PHONE_PHONETIC_NAME_COLUMN_INDEX);
}
diff --git a/src/com/android/contacts/list/PostalAddressPickerFragment.java b/src/com/android/contacts/list/PostalAddressPickerFragment.java
index f14b718..5f7ca56 100644
--- a/src/com/android/contacts/list/PostalAddressPickerFragment.java
+++ b/src/com/android/contacts/list/PostalAddressPickerFragment.java
@@ -73,7 +73,7 @@
return inflater.inflate(R.layout.contacts_list_content, null);
}
- public void pickPostalAddress(Uri uri) {
+ private void pickPostalAddress(Uri uri) {
mListener.onPickPostalAddressAction(uri);
}
}
diff --git a/src/com/android/contacts/list/ShortcutIntentBuilder.java b/src/com/android/contacts/list/ShortcutIntentBuilder.java
index 101b6d5..43a6c1e 100644
--- a/src/com/android/contacts/list/ShortcutIntentBuilder.java
+++ b/src/com/android/contacts/list/ShortcutIntentBuilder.java
@@ -75,7 +75,7 @@
private final OnShortcutIntentCreatedListener mListener;
private final Context mContext;
- private final int mIconSize;
+ private int mIconSize;
private final int mIconDensity;
/**
@@ -99,7 +99,10 @@
final ActivityManager am = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
- mIconSize = am.getLauncherLargeIconSize();
+ mIconSize = context.getResources().getDimensionPixelSize(R.dimen.shortcut_icon_size);
+ if (mIconSize == 0) {
+ mIconSize = am.getLauncherLargeIconSize();
+ }
mIconDensity = am.getLauncherLargeIconDensity();
}
diff --git a/src/com/android/contacts/model/AccountType.java b/src/com/android/contacts/model/AccountType.java
index 0f67fba..462f7ad 100644
--- a/src/com/android/contacts/model/AccountType.java
+++ b/src/com/android/contacts/model/AccountType.java
@@ -30,15 +30,12 @@
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
-import android.view.View;
import android.widget.EditText;
-import java.text.SimpleDateFormat;
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
@@ -160,82 +157,6 @@
}
/**
- * Description of a specific data type, usually marked by a unique
- * {@link Data#MIMETYPE}. Includes details about how to view and edit
- * {@link Data} rows of this kind, including the possible {@link EditType}
- * labels and editable {@link EditField}.
- */
- public static class DataKind {
- public String resPackageName;
- public String mimeType;
- public int titleRes;
- public int iconRes;
- public int iconAltRes;
- public int weight;
- public boolean editable;
-
- /**
- * If this is true (default), the user can add and remove values.
- * If false, the editor will always show a single field (which might be empty).
- */
- public boolean isList;
-
- public StringInflater actionHeader;
- public StringInflater actionAltHeader;
- public StringInflater actionBody;
-
- public boolean actionBodySocial = false;
-
- public String typeColumn;
-
- /**
- * Maximum number of values allowed in the list. -1 represents infinity.
- * If {@link DataKind#isList} is false, this value is ignored.
- */
- public int typeOverallMax;
-
- public List<EditType> typeList;
- public List<EditField> fieldList;
-
- public ContentValues defaultValues;
-
- public Class<? extends View> editorClass;
-
- /**
- * 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;
-
- public DataKind() {
- }
-
- public DataKind(String mimeType, int titleRes, int iconRes, int weight, boolean editable) {
- this(mimeType, titleRes, iconRes, weight, editable, null);
- }
-
- public DataKind(String mimeType, int titleRes, int iconRes, int weight, boolean editable,
- Class<? extends View> editorClass) {
- this.mimeType = mimeType;
- this.titleRes = titleRes;
- this.iconRes = iconRes;
- this.weight = weight;
- this.editable = editable;
- this.isList = true;
- this.typeOverallMax = -1;
- this.editorClass = editorClass;
- }
- }
-
- /**
* 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
@@ -245,6 +166,10 @@
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;
@@ -324,6 +249,7 @@
public boolean optional;
public boolean shortForm;
public boolean longForm;
+ public boolean isFullName;
public EditField(String column, int titleRes) {
this.column = column;
@@ -354,6 +280,11 @@
this.minLines = minLines;
return this;
}
+
+ public EditField setIsFullName(boolean isFullName) {
+ this.isFullName = isFullName;
+ return this;
+ }
}
/**
diff --git a/src/com/android/contacts/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java
index 06bb9bd..58195a1 100644
--- a/src/com/android/contacts/model/AccountTypeManager.java
+++ b/src/com/android/contacts/model/AccountTypeManager.java
@@ -16,7 +16,6 @@
package com.android.contacts.model;
-import com.android.contacts.model.AccountType.DataKind;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
diff --git a/src/com/android/contacts/model/BaseAccountType.java b/src/com/android/contacts/model/BaseAccountType.java
index dbfeae4..fd8f914 100644
--- a/src/com/android/contacts/model/BaseAccountType.java
+++ b/src/com/android/contacts/model/BaseAccountType.java
@@ -99,13 +99,44 @@
protected DataKind addDataKindStructuredName(Context context) {
DataKind kind = addKind(new DataKind(StructuredName.CONTENT_ITEM_TYPE,
- R.string.nameLabelsGroup, -1, -1, true));
+ R.string.nameLabelsGroup, -1, -1, true, R.layout.structured_name_editor_view,
+ android.R.style.TextAppearance_Large, -1));
kind.actionHeader = new SimpleInflater(R.string.nameLabelsGroup);
kind.actionBody = new SimpleInflater(Nickname.NAME);
kind.fieldList = Lists.newArrayList();
kind.fieldList.add(new EditField(StructuredName.DISPLAY_NAME,
- R.string.full_name, FLAGS_PERSON_NAME).setShortForm(true));
+ 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) {
+ DataKind kind = addKind(new DataKind(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME,
+ R.string.nameLabelsGroup, -1, -1, true, R.layout.text_fields_editor_view,
+ android.R.style.TextAppearance_Large, -1));
+ kind.actionHeader = new SimpleInflater(R.string.nameLabelsGroup);
+ kind.actionBody = new SimpleInflater(Nickname.NAME);
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(StructuredName.DISPLAY_NAME,
+ R.string.full_name, FLAGS_PERSON_NAME).setShortForm(true).setIsFullName(true));
boolean displayOrderPrimary =
context.getResources().getBoolean(R.bool.config_editor_field_order_primary);
@@ -121,12 +152,6 @@
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).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));
} else {
kind.fieldList.add(new EditField(StructuredName.PREFIX, R.string.name_prefix,
FLAGS_PERSON_NAME).setLongForm(true));
@@ -138,21 +163,35 @@
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_GIVEN_NAME,
- R.string.name_phonetic_given, 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_FAMILY_NAME,
- R.string.name_phonetic_family, FLAGS_PHONETIC).setLongForm(true));
}
return kind;
}
+ protected DataKind addDataKindPhoneticName(Context context) {
+ DataKind kind = addKind(new DataKind(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME,
+ R.string.name_phonetic, -1, -1, true, R.layout.phonetic_name_editor_view,
+ android.R.style.TextAppearance_Medium, -1));
+ kind.actionHeader = new SimpleInflater(R.string.nameLabelsGroup);
+ kind.actionBody = new SimpleInflater(Nickname.NAME);
+
+ 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) {
DataKind kind = addKind(new DataKind(Nickname.CONTENT_ITEM_TYPE,
- R.string.nicknameLabelsGroup, -1, 115, true));
-
+ R.string.nicknameLabelsGroup, -1, 115, true,
+ R.layout.text_fields_editor_view, android.R.style.TextAppearance_Medium, -1));
kind.isList = false;
kind.actionHeader = new SimpleInflater(R.string.nicknameLabelsGroup);
kind.actionBody = new SimpleInflater(Nickname.NAME);
@@ -168,7 +207,9 @@
protected DataKind addDataKindPhone(Context context) {
DataKind kind = addKind(new DataKind(Phone.CONTENT_ITEM_TYPE, R.string.phoneLabelsGroup,
- android.R.drawable.sym_action_call, 10, true));
+ android.R.drawable.sym_action_call, 10, true,
+ R.layout.text_fields_editor_view, android.R.style.TextAppearance_Large,
+ R.string.add_phone));
kind.iconAltRes = R.drawable.sym_action_sms;
kind.actionHeader = new PhoneActionInflater();
kind.actionAltHeader = new PhoneActionAltInflater();
@@ -207,7 +248,9 @@
protected DataKind addDataKindEmail(Context context) {
DataKind kind = addKind(new DataKind(Email.CONTENT_ITEM_TYPE, R.string.emailLabelsGroup,
- R.drawable.sym_action_email_holo_light, 15, true));
+ R.drawable.sym_action_email_holo_light, 15, true,
+ R.layout.text_fields_editor_view, android.R.style.TextAppearance_Medium,
+ R.string.add_email));
kind.actionHeader = new EmailActionInflater();
kind.actionBody = new SimpleInflater(Email.DATA);
kind.typeColumn = Email.TYPE;
@@ -228,7 +271,8 @@
protected DataKind addDataKindStructuredPostal(Context context) {
DataKind kind = addKind(new DataKind(StructuredPostal.CONTENT_ITEM_TYPE,
R.string.postalLabelsGroup, R.drawable.sym_action_show_map_holo_light, 25,
- true));
+ true, R.layout.text_fields_editor_view, android.R.style.TextAppearance_Medium,
+ R.string.add_address));
kind.actionHeader = new PostalActionInflater();
kind.actionBody = new SimpleInflater(StructuredPostal.FORMATTED_ADDRESS);
kind.typeColumn = StructuredPostal.TYPE;
@@ -249,7 +293,9 @@
protected DataKind addDataKindIm(Context context) {
DataKind kind = addKind(new DataKind(Im.CONTENT_ITEM_TYPE, R.string.imLabelsGroup,
- R.drawable.sym_action_talk_holo_light, 20, true));
+ R.drawable.sym_action_talk_holo_light, 20, true,
+ R.layout.text_fields_editor_view, android.R.style.TextAppearance_Medium,
+ R.string.add_im));
kind.actionHeader = new ImActionInflater();
kind.actionBody = new SimpleInflater(Im.DATA);
@@ -280,7 +326,8 @@
protected DataKind addDataKindOrganization(Context context) {
DataKind kind = addKind(new DataKind(Organization.CONTENT_ITEM_TYPE,
- R.string.organizationLabelsGroup, -1, 5, true));
+ R.string.organizationLabelsGroup, -1, 5, true,
+ R.layout.text_fields_editor_view, android.R.style.TextAppearance_Medium, -1));
kind.actionHeader = new SimpleInflater(Organization.COMPANY);
kind.actionBody = new SimpleInflater(Organization.TITLE);
kind.isList = false;
@@ -295,7 +342,8 @@
}
protected DataKind addDataKindPhoto(Context context) {
- DataKind kind = addKind(new DataKind(Photo.CONTENT_ITEM_TYPE, -1, -1, -1, true));
+ DataKind kind = addKind(new DataKind(Photo.CONTENT_ITEM_TYPE, -1, -1, -1, true, -1,
+ android.R.style.TextAppearance_Medium, -1));
kind.fieldList = Lists.newArrayList();
kind.fieldList.add(new EditField(Photo.PHOTO, -1, -1));
return kind;
@@ -303,7 +351,9 @@
protected DataKind addDataKindNote(Context context) {
DataKind kind = addKind(new DataKind(Note.CONTENT_ITEM_TYPE,
- R.string.label_notes, -1, 110, true));
+ R.string.label_notes, -1, 110, true,
+ R.layout.text_fields_editor_view, android.R.style.TextAppearance_Medium,
+ R.string.add_note));
kind.isList = false;
kind.actionHeader = new SimpleInflater(R.string.label_notes);
kind.actionBody = new SimpleInflater(Note.NOTE);
@@ -316,7 +366,8 @@
protected DataKind addDataKindWebsite(Context context) {
DataKind kind = addKind(new DataKind(Website.CONTENT_ITEM_TYPE,
R.string.websiteLabelsGroup, R.drawable.sym_action_goto_website_holo_light, 120,
- true));
+ true, R.layout.text_fields_editor_view, android.R.style.TextAppearance_Medium,
+ R.string.add_website));
kind.actionHeader = new SimpleInflater(R.string.websiteLabelsGroup);
kind.actionBody = new SimpleInflater(Website.URL);
kind.defaultValues = new ContentValues();
@@ -338,7 +389,9 @@
// the android:icon attribute of the SIP-related
// intent-filters in the Phone app's manifest.
DataKind kind = addKind(new DataKind(SipAddress.CONTENT_ITEM_TYPE,
- R.string.label_sip_address, android.R.drawable.sym_action_call, 130, true));
+ R.string.label_sip_address, android.R.drawable.sym_action_call, 130, true,
+ R.layout.text_fields_editor_view, android.R.style.TextAppearance_Medium,
+ -1));
kind.isList = false;
kind.actionHeader = new SimpleInflater(R.string.label_sip_address);
@@ -353,7 +406,8 @@
protected DataKind addDataKindGroupMembership(Context context) {
DataKind kind = getKindForMimetype(GroupMembership.CONTENT_ITEM_TYPE);
kind = addKind(new DataKind(GroupMembership.CONTENT_ITEM_TYPE,
- R.string.groupsLabel, android.R.drawable.sym_contact_card, 999, true));
+ R.string.groupsLabel, android.R.drawable.sym_contact_card, 999, true, -1,
+ android.R.style.TextAppearance_Medium, -1));
kind.isList = false;
kind.fieldList = Lists.newArrayList();
diff --git a/src/com/android/contacts/model/DataKind.java b/src/com/android/contacts/model/DataKind.java
new file mode 100644
index 0000000..52769c3
--- /dev/null
+++ b/src/com/android/contacts/model/DataKind.java
@@ -0,0 +1,106 @@
+package com.android.contacts.model;
+
+import com.android.contacts.R;
+import com.android.contacts.model.AccountType.EditField;
+import com.android.contacts.model.AccountType.EditType;
+import com.android.contacts.model.AccountType.StringInflater;
+
+import android.content.ContentValues;
+import android.provider.ContactsContract.Data;
+
+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 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 resPackageName;
+ public String mimeType;
+ public int titleRes;
+ public int iconRes;
+ public int iconAltRes;
+ public int weight;
+ public boolean editable;
+
+ /**
+ * If this is true (default), the user can add and remove values.
+ * If false, the editor will always show a single field (which might be empty).
+ */
+ public boolean isList;
+
+ public StringInflater actionHeader;
+ public StringInflater actionAltHeader;
+ public StringInflater actionBody;
+
+ public boolean actionBodySocial = false;
+
+ public String typeColumn;
+
+ /**
+ * Maximum number of values allowed in the list. -1 represents infinity.
+ * If {@link DataKind#isList} is false, this value is ignored.
+ */
+ public int typeOverallMax;
+
+ public List<EditType> typeList;
+ public List<EditField> fieldList;
+
+ public ContentValues defaultValues;
+
+ /** Layout resource id for an editor view to edit this {@link DataKind}. */
+ public final int editorLayoutResourceId;
+
+ /** Text appearance resource id for the value of a field in this {@link DataKind}. */
+ public final int textAppearanceResourceId;
+
+ /**
+ * String resource id for the "add field" footer. This is equal to -1 if it
+ * is not applicable to add a new field to this class (i.e. for a structured
+ * name because a user should only have one structured name).
+ */
+ public final int addNewFieldTextResourceId;
+
+ /**
+ * 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;
+
+ public DataKind() {
+ editorLayoutResourceId = R.layout.text_fields_editor_view;
+ textAppearanceResourceId = android.R.style.TextAppearance_Medium;
+ addNewFieldTextResourceId = -1;
+ }
+
+ public DataKind(String mimeType, int titleRes, int iconRes, int weight, boolean editable,
+ int editorLayoutResourceId, int textAppearanceResourceId,
+ int addNewFieldTextResourceId) {
+ this.mimeType = mimeType;
+ this.titleRes = titleRes;
+ this.iconRes = iconRes;
+ this.weight = weight;
+ this.editable = editable;
+ this.isList = true;
+ this.typeOverallMax = -1;
+ this.editorLayoutResourceId = editorLayoutResourceId;
+ this.textAppearanceResourceId = textAppearanceResourceId;
+ this.addNewFieldTextResourceId = addNewFieldTextResourceId;
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/model/EntityDelta.java b/src/com/android/contacts/model/EntityDelta.java
index c5d0d9e..fe084f4 100644
--- a/src/com/android/contacts/model/EntityDelta.java
+++ b/src/com/android/contacts/model/EntityDelta.java
@@ -330,7 +330,7 @@
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("\n(");
- builder.append(mValues.toString());
+ builder.append(mValues != null ? mValues.toString() : "null");
builder.append(") = {");
for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
for (ValuesDelta child : mimeEntries) {
diff --git a/src/com/android/contacts/model/EntityDeltaList.java b/src/com/android/contacts/model/EntityDeltaList.java
index a998a37..9b7bdc6 100644
--- a/src/com/android/contacts/model/EntityDeltaList.java
+++ b/src/com/android/contacts/model/EntityDeltaList.java
@@ -340,10 +340,18 @@
mSplitRawContacts = true;
}
+ public boolean isMarkedForSplitting() {
+ return mSplitRawContacts;
+ }
+
public void setJoinWithRawContacts(long[] rawContactIds) {
mJoinWithRawContactIds = rawContactIds;
}
+ public boolean isMarkedForJoining() {
+ return mJoinWithRawContactIds != null && mJoinWithRawContactIds.length > 0;
+ }
+
/** {@inheritDoc} */
public int describeContents() {
// Nothing special about this parcel
@@ -358,6 +366,7 @@
dest.writeParcelable(delta, flags);
}
dest.writeLongArray(mJoinWithRawContactIds);
+ dest.writeInt(mSplitRawContacts ? 1 : 0);
}
@SuppressWarnings("unchecked")
@@ -368,6 +377,7 @@
this.add(source.<EntityDelta> readParcelable(loader));
}
mJoinWithRawContactIds = source.createLongArray();
+ mSplitRawContacts = source.readInt() != 0;
}
public static final Parcelable.Creator<EntityDeltaList> CREATOR =
diff --git a/src/com/android/contacts/model/EntityModifier.java b/src/com/android/contacts/model/EntityModifier.java
index c58d813..9d527df 100644
--- a/src/com/android/contacts/model/EntityModifier.java
+++ b/src/com/android/contacts/model/EntityModifier.java
@@ -17,37 +17,56 @@
package com.android.contacts.model;
import com.android.contacts.ContactsUtils;
-import com.android.contacts.model.AccountType.DataKind;
+import com.android.contacts.editor.EventFieldEditorView;
+import com.android.contacts.util.NameConverter;
+import com.android.contacts.editor.PhoneticNameEditorView;
import com.android.contacts.model.AccountType.EditField;
import com.android.contacts.model.AccountType.EditType;
+import com.android.contacts.model.AccountType.EventEditType;
import com.android.contacts.model.EntityDelta.ValuesDelta;
-import com.google.android.collect.Lists;
+import com.android.contacts.util.DateUtils;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
+import android.net.Uri;
import android.os.Bundle;
-import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.Intents;
-import android.provider.ContactsContract.RawContacts;
+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.SparseIntArray;
+import java.text.ParsePosition;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
/**
* Helper methods for modifying an {@link EntityDelta}, such as inserting
@@ -135,7 +154,7 @@
*/
private static ArrayList<EditType> getValidTypes(EntityDelta state, DataKind kind,
EditType forceInclude, boolean includeSecondary, SparseIntArray typeCount) {
- final ArrayList<EditType> validTypes = Lists.newArrayList();
+ final ArrayList<EditType> validTypes = new ArrayList<EditType>();
// Bail early if no types provided
if (!hasEditTypes(kind)) return validTypes;
@@ -344,7 +363,7 @@
}
final ValuesDelta child = ValuesDelta.fromAfter(after);
- state.addEntry(child);
+ state.addEntry(child);
return child;
}
@@ -357,11 +376,26 @@
public static void trimEmpty(EntityDeltaList set, AccountTypeManager accountTypes) {
for (EntityDelta state : set) {
final String accountType = state.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
- final AccountType source = accountTypes.getAccountType(accountType);
- trimEmpty(state, source);
+ final AccountType type = accountTypes.getAccountType(accountType);
+ trimEmpty(state, type);
}
}
+ public static boolean hasChanges(EntityDeltaList set, AccountTypeManager accountTypes) {
+ if (set.isMarkedForSplitting() || set.isMarkedForJoining()) {
+ return true;
+ }
+
+ for (EntityDelta state : set) {
+ final String accountType = state.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
+ final AccountType type = accountTypes.getAccountType(accountType);
+ if (hasChanges(state, type)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Processing to trim any empty {@link ValuesDelta} rows from the given
* {@link EntityDelta}, assuming the given {@link AccountType} dictates
@@ -406,24 +440,45 @@
}
}
+ private static boolean hasChanges(EntityDelta state, AccountType accountType) {
+ 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) {
+ // 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;
- boolean hasValues = false;
for (EditField field : kind.fieldList) {
// If any field has values, we're not empty
final String value = values.getAsString(field.column);
if (ContactsUtils.isGraphic(value)) {
- hasValues = true;
+ return false;
}
}
- return !hasValues;
+ return true;
}
/**
@@ -455,28 +510,8 @@
return;
}
- {
- // StructuredName
- EntityModifier.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)) {
- child.put(StructuredName.DISPLAY_NAME, name);
- }
-
- final String phoneticName = extras.getString(Insert.PHONETIC_NAME);
- if (ContactsUtils.isGraphic(phoneticName)) {
- child.put(StructuredName.PHONETIC_GIVEN_NAME, phoneticName);
- }
- }
-
- {
- // StructuredPostal
- final DataKind kind = accountType.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE);
- parseExtras(state, kind, extras, Insert.POSTAL_TYPE, Insert.POSTAL,
- StructuredPostal.FORMATTED_ADDRESS);
- }
+ parseStructuredNameExtra(context, accountType, state, extras);
+ parseStructuredPostalExtra(accountType, state, extras);
{
// Phone
@@ -542,6 +577,87 @@
}
}
+ private static void parseStructuredNameExtra(
+ Context context, AccountType accountType, EntityDelta state, Bundle extras) {
+ // StructuredName
+ EntityModifier.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);
+
+ 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)) {
+ child.put(StructuredName.PHONETIC_GIVEN_NAME, phoneticName);
+ }
+ }
+
+ private static void parseStructuredPostalExtra(
+ AccountType accountType, EntityDelta 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(
EntityDelta state, AccountType accountType, ArrayList<ContentValues> dataValueList) {
for (ContentValues values : dataValueList) {
@@ -721,6 +837,7 @@
* 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;
@@ -748,17 +865,17 @@
* @param valueExtra {@link Bundle} key that holds the incoming value.
* @param valueColumn Column to write value into {@link ValuesDelta}.
*/
- public static void parseExtras(EntityDelta state, DataKind kind, Bundle extras,
+ public static ValuesDelta parseExtras(EntityDelta 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;
+ if (kind == null) return null;
// Bail when can't insert type, or value missing
final boolean canInsert = EntityModifier.canInsert(state, kind);
final boolean validValue = (value != null && TextUtils.isGraphic(value));
- if (!validValue || !canInsert) return;
+ if (!validValue || !canInsert) return null;
// Find exact type when requested, otherwise best available type
final boolean hasType = extras.containsKey(typeExtra);
@@ -775,5 +892,506 @@
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 EntityDelta 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,
+ EntityDelta oldState, EntityDelta 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()) {
+ final String mimeType = kind.mimeType;
+ final int fieldCount = kind.fieldList.size();
+ final Set<String> allowedColumns = new HashSet<String>();
+ if (DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME.equals(mimeType)
+ || DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(mimeType)) {
+ // Ignore pseude 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 {
+ migrateGenericWithTypeColumn(oldState, newState, kind);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks {@link DataKind#isList} and {@link DataKind#typeOverallMax}, and restricts
+ * the number of entries (ValuesDelta) inside newState.
+ */
+ private static ArrayList<ValuesDelta> ensureEntryMaxSize(EntityDelta newState, DataKind kind,
+ ArrayList<ValuesDelta> mimeEntries) {
+ if (mimeEntries == null) {
+ return null;
+ }
+
+ int typeOverallMax = kind.typeOverallMax;
+ if (!kind.isList) {
+ typeOverallMax = 1;
+ }
+ 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, EntityDelta oldState, EntityDelta 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 ContentValues tmpValues =
+ PhoneticNameEditorView.parsePhoneticName(phoneticFullName, null);
+ values.remove(DataKind.PSEUDO_COLUMN_PHONETIC_NAME);
+ if (supportPhoneticFamilyName) {
+ values.put(StructuredName.PHONETIC_FAMILY_NAME,
+ tmpValues.getAsString(StructuredName.PHONETIC_FAMILY_NAME));
+ } else {
+ values.remove(StructuredName.PHONETIC_FAMILY_NAME);
+ }
+ if (supportPhoneticMiddleName) {
+ values.put(StructuredName.PHONETIC_MIDDLE_NAME,
+ tmpValues.getAsString(StructuredName.PHONETIC_MIDDLE_NAME));
+ } else {
+ values.remove(StructuredName.PHONETIC_MIDDLE_NAME);
+ }
+ if (supportPhoneticGivenName) {
+ values.put(StructuredName.PHONETIC_GIVEN_NAME,
+ tmpValues.getAsString(StructuredName.PHONETIC_GIVEN_NAME));
+ } 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,
+ PhoneticNameEditorView.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(EntityDelta oldState, EntityDelta 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(EntityDelta oldState, EntityDelta 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 Map<Integer, EventEditType> allowedTypes = new HashMap<Integer, 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.containsKey(type) && !TextUtils.isEmpty(dateString)) {
+ EventEditType suitableType = allowedTypes.get(type);
+
+ final ParsePosition position = new ParsePosition(0);
+ boolean yearOptional = false;
+ Date date = DateUtils.DATE_AND_TIME_FORMAT.parse(dateString, position);
+ if (date == null) {
+ yearOptional = true;
+ date = DateUtils.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,
+ EventFieldEditorView.getDefaultHourForBirthday(), 0, 0);
+ values.put(Event.START_DATE,
+ DateUtils.FULL_DATE_FORMAT.format(calendar.getTime()));
+ }
+ }
+ newState.addEntry(ValuesDelta.fromAfter(values));
+ } else {
+ // Just drop it.
+ }
+ }
+ }
+
+ /** @hide Public only for testing. */
+ public static void migrateGenericWithoutTypeColumn(
+ EntityDelta oldState, EntityDelta 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(
+ EntityDelta oldState, EntityDelta newState, DataKind newDataKind) {
+ if (!sGenericMimeTypesWithTypeSupport.contains(newDataKind.mimeType)) {
+ throw new RuntimeException("not supported: " + newDataKind.mimeType);
+ }
+
+ 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 Map<Integer, Integer> typeSpecificMaxMap = new HashMap<Integer, Integer>();
+ 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.isList ? newDataKind.typeOverallMax : 1;
+
+ // key: type, value: the number of current entries.
+ final Map<Integer, Integer> currentEntryCount = new HashMap<Integer, Integer>();
+ 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.containsKey(typeForNewAccount) ?
+ typeSpecificMaxMap.get(typeForNewAccount) : 0);
+ if (specificMax >= 0) {
+ final int currentCount = (currentEntryCount.get(typeForNewAccount) != null ?
+ 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/model/ExchangeAccountType.java b/src/com/android/contacts/model/ExchangeAccountType.java
index 4442a70..22a2ba2 100644
--- a/src/com/android/contacts/model/ExchangeAccountType.java
+++ b/src/com/android/contacts/model/ExchangeAccountType.java
@@ -17,7 +17,6 @@
package com.android.contacts.model;
import com.android.contacts.R;
-import com.android.contacts.editor.EventFieldEditorView;
import com.android.contacts.util.DateUtils;
import com.google.android.collect.Lists;
@@ -47,6 +46,8 @@
this.summaryResPackageName = resPackageName;
addDataKindStructuredName(context);
+ addDataKindDisplayName(context);
+ addDataKindPhoneticName(context);
addDataKindNickname(context);
addDataKindPhone(context);
addDataKindEmail(context);
@@ -62,7 +63,39 @@
@Override
protected DataKind addDataKindStructuredName(Context context) {
- final DataKind kind = super.addDataKindStructuredName(context);
+ DataKind kind = addKind(new DataKind(StructuredName.CONTENT_ITEM_TYPE,
+ R.string.nameLabelsGroup, -1, -1, true,
+ R.layout.structured_name_editor_view, android.R.style.TextAppearance_Large, -1));
+ 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) {
+ DataKind kind = addKind(new DataKind(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME,
+ R.string.nameLabelsGroup, -1, -1, true,
+ R.layout.text_fields_editor_view, android.R.style.TextAppearance_Large, -1));
boolean displayOrderPrimary =
context.getResources().getBoolean(R.bool.config_editor_field_order_primary);
@@ -78,12 +111,6 @@
R.string.name_middle, FLAGS_PERSON_NAME).setOptional(true));
kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME,
R.string.name_given, FLAGS_PERSON_NAME));
- kind.fieldList.add(new EditField(StructuredName.SUFFIX,
- R.string.name_suffix, FLAGS_PERSON_NAME).setOptional(true));
- kind.fieldList.add(new EditField(StructuredName.PHONETIC_FAMILY_NAME,
- R.string.name_phonetic_family, FLAGS_PHONETIC).setOptional(true));
- kind.fieldList.add(new EditField(StructuredName.PHONETIC_GIVEN_NAME,
- R.string.name_phonetic_given, FLAGS_PHONETIC).setOptional(true));
} else {
kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME,
R.string.name_given, FLAGS_PERSON_NAME));
@@ -91,13 +118,28 @@
R.string.name_middle, FLAGS_PERSON_NAME).setOptional(true));
kind.fieldList.add(new EditField(StructuredName.FAMILY_NAME,
R.string.name_family, FLAGS_PERSON_NAME));
- kind.fieldList.add(new EditField(StructuredName.SUFFIX,
- R.string.name_suffix, FLAGS_PERSON_NAME).setOptional(true));
- kind.fieldList.add(new EditField(StructuredName.PHONETIC_GIVEN_NAME,
- R.string.name_phonetic_given, FLAGS_PHONETIC).setOptional(true));
- kind.fieldList.add(new EditField(StructuredName.PHONETIC_FAMILY_NAME,
- R.string.name_phonetic_family, FLAGS_PHONETIC).setOptional(true));
}
+ kind.fieldList.add(new EditField(StructuredName.SUFFIX,
+ R.string.name_suffix, FLAGS_PERSON_NAME).setOptional(true));
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind addDataKindPhoneticName(Context context) {
+ DataKind kind = addKind(new DataKind(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME,
+ R.string.name_phonetic, -1, -1, true,
+ R.layout.phonetic_name_editor_view, android.R.style.TextAppearance_Medium, -1));
+ 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;
}
@@ -252,7 +294,9 @@
protected DataKind addDataKindEvent(Context context) {
DataKind kind = addKind(
- new DataKind(Event.CONTENT_ITEM_TYPE, R.string.eventLabelsGroup, -1, 150, true));
+ new DataKind(Event.CONTENT_ITEM_TYPE, R.string.eventLabelsGroup, -1, 150, true,
+ R.layout.event_field_editor_view, android.R.style.TextAppearance_Medium,
+ R.string.add_event));
kind.actionHeader = new EventActionInflater();
kind.actionBody = new SimpleInflater(Event.START_DATE);
@@ -263,7 +307,6 @@
kind.typeList.add(buildEventType(Event.TYPE_BIRTHDAY, false).setSpecificMax(1));
kind.dateFormatWithYear = DateUtils.DATE_AND_TIME_FORMAT;
- kind.editorClass = EventFieldEditorView.class;
kind.fieldList = Lists.newArrayList();
kind.fieldList.add(new EditField(Event.DATA, R.string.eventLabelsGroup, FLAGS_EVENT));
diff --git a/src/com/android/contacts/model/ExternalAccountType.java b/src/com/android/contacts/model/ExternalAccountType.java
index 0b895f6..9ce6fd9 100644
--- a/src/com/android/contacts/model/ExternalAccountType.java
+++ b/src/com/android/contacts/model/ExternalAccountType.java
@@ -73,6 +73,8 @@
// Bring in name and photo from fallback source, which are non-optional
addDataKindStructuredName(context);
+ addDataKindDisplayName(context);
+ addDataKindPhoneticName(context);
addDataKindPhoto(context);
}
diff --git a/src/com/android/contacts/model/FallbackAccountType.java b/src/com/android/contacts/model/FallbackAccountType.java
index 05e6556..13540be 100644
--- a/src/com/android/contacts/model/FallbackAccountType.java
+++ b/src/com/android/contacts/model/FallbackAccountType.java
@@ -31,6 +31,8 @@
this.summaryResPackageName = resPackageName;
addDataKindStructuredName(context);
+ addDataKindDisplayName(context);
+ addDataKindPhoneticName(context);
addDataKindNickname(context);
addDataKindPhone(context);
addDataKindEmail(context);
diff --git a/src/com/android/contacts/model/GoogleAccountType.java b/src/com/android/contacts/model/GoogleAccountType.java
index d369b28..bd445b1 100644
--- a/src/com/android/contacts/model/GoogleAccountType.java
+++ b/src/com/android/contacts/model/GoogleAccountType.java
@@ -17,7 +17,6 @@
package com.android.contacts.model;
import com.android.contacts.R;
-import com.android.contacts.editor.EventFieldEditorView;
import com.android.contacts.util.DateUtils;
import com.google.android.collect.Lists;
@@ -40,6 +39,8 @@
this.summaryResPackageName = resPackageName;
addDataKindStructuredName(context);
+ addDataKindDisplayName(context);
+ addDataKindPhoneticName(context);
addDataKindNickname(context);
addDataKindPhone(context);
addDataKindEmail(context);
@@ -61,9 +62,10 @@
kind.typeColumn = Phone.TYPE;
kind.typeList = Lists.newArrayList();
- kind.typeList.add(buildPhoneType(Phone.TYPE_HOME));
kind.typeList.add(buildPhoneType(Phone.TYPE_MOBILE));
kind.typeList.add(buildPhoneType(Phone.TYPE_WORK));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_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));
@@ -97,7 +99,9 @@
private DataKind addDataKindRelation(Context context) {
DataKind kind = addKind(new DataKind(Relation.CONTENT_ITEM_TYPE,
- R.string.relationLabelsGroup, -1, 160, true));
+ R.string.relationLabelsGroup, -1, 160, true,
+ R.layout.text_fields_editor_view, android.R.style.TextAppearance_Medium,
+ R.string.add_relationship));
kind.actionHeader = new RelationActionInflater();
kind.actionBody = new SimpleInflater(Relation.NAME);
@@ -132,10 +136,11 @@
private DataKind addDataKindEvent(Context context) {
DataKind kind = addKind(new DataKind(Event.CONTENT_ITEM_TYPE,
- R.string.eventLabelsGroup, -1, 150, true));
+ R.string.eventLabelsGroup, -1, 150, true,
+ R.layout.event_field_editor_view, android.R.style.TextAppearance_Medium,
+ R.string.add_event));
kind.actionHeader = new EventActionInflater();
kind.actionBody = new SimpleInflater(Event.START_DATE);
- kind.editorClass = EventFieldEditorView.class;
kind.typeColumn = Event.TYPE;
kind.typeList = Lists.newArrayList();
diff --git a/src/com/android/contacts/quickcontact/DataAction.java b/src/com/android/contacts/quickcontact/DataAction.java
index bd59856..787d482 100644
--- a/src/com/android/contacts/quickcontact/DataAction.java
+++ b/src/com/android/contacts/quickcontact/DataAction.java
@@ -2,7 +2,7 @@
import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType.DataKind;
+import com.android.contacts.model.DataKind;
import com.android.contacts.util.Constants;
import com.android.contacts.util.PhoneCapabilityTester;
diff --git a/src/com/android/contacts/quickcontact/FloatingChildLayout.java b/src/com/android/contacts/quickcontact/FloatingChildLayout.java
new file mode 100644
index 0000000..ddba609
--- /dev/null
+++ b/src/com/android/contacts/quickcontact/FloatingChildLayout.java
@@ -0,0 +1,231 @@
+/*
+ * 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.quickcontact;
+
+import com.android.contacts.R;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationUtils;
+import android.widget.FrameLayout;
+import android.widget.PopupWindow;
+
+/**
+ * Layout containing single child {@link View} which it attempts to center
+ * around {@link #setChildTargetScreen(Rect)}.
+ * <p>
+ * Updates drawable state to be {@link android.R.attr#state_first} when child is
+ * above target, and {@link android.R.attr#state_last} when child is below
+ * target. Also updates {@link Drawable#setLevel(int)} on child
+ * {@link View#getBackground()} to reflect horizontal center of target.
+ * <p>
+ * The reason for this approach is because target {@link Rect} is in screen
+ * coordinates disregarding decor insets; otherwise something like
+ * {@link PopupWindow} might work better.
+ */
+public class FloatingChildLayout extends FrameLayout {
+ private static final String TAG = "FloatingChild";
+
+ public FloatingChildLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ private View mChild;
+
+ private Rect mTargetScreen = new Rect();
+
+ private int mCalloutState = 0;
+ private int mCalloutLeft;
+
+ @Override
+ protected void onFinishInflate() {
+ mChild = findViewById(android.R.id.content);
+ mChild.setDuplicateParentStateEnabled(true);
+ }
+
+ public View getChild() {
+ return mChild;
+ }
+
+ /**
+ * Set {@link Rect} in screen coordinates that {@link #getChild()} should be
+ * centered around.
+ */
+ public void setChildTargetScreen(Rect targetScreen) {
+ mTargetScreen = targetScreen;
+ requestLayout();
+ }
+
+ /**
+ * Return {@link #mTargetScreen} in local window coordinates, taking any
+ * decor insets into account.
+ */
+ private Rect getTargetInWindow() {
+ final Rect windowScreen = new Rect();
+ getWindowVisibleDisplayFrame(windowScreen);
+
+ final Rect target = new Rect(mTargetScreen);
+ target.offset(-windowScreen.left, -windowScreen.top);
+ return target;
+ }
+
+ private void updateCallout(int calloutState, int calloutLeft) {
+ if (mCalloutState != calloutState) {
+ mCalloutState = calloutState;
+ mChild.refreshDrawableState();
+ }
+
+ final Drawable background = mChild.getBackground();
+ if (background != null && mCalloutLeft != calloutLeft) {
+ mCalloutLeft = calloutLeft;
+ background.setLevel(calloutLeft);
+ }
+ }
+
+ @Override
+ protected int[] onCreateDrawableState(int extraSpace) {
+ final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+ mergeDrawableStates(drawableState, new int[] { mCalloutState });
+ return drawableState;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+
+ final View child = mChild;
+ final Rect target = getTargetInWindow();
+
+ final int childWidth = child.getMeasuredWidth();
+ final int childHeight = child.getMeasuredHeight();
+
+ // default is no callout, left-aligned, and vertically centered
+ int calloutState = 0;
+ int childLeft = target.left;
+ int childTop = target.centerY() - (childHeight / 2);
+
+ // when target is wide, horizontally center instead of left-align
+ if (target.width() > childWidth / 2) {
+ childLeft = target.centerX() - (childWidth / 2);
+ }
+
+ final int areaAboveTarget = target.top;
+ final int areaBelowTarget = getHeight() - target.bottom;
+
+ if (areaAboveTarget >= childHeight) {
+ // enough room above target, place above and callout down
+ calloutState = android.R.attr.state_first;
+ childTop = target.top - childHeight;
+
+ } else if (areaBelowTarget >= childHeight) {
+ // enough room below target, place below and callout up
+ calloutState = android.R.attr.state_last;
+ childTop = target.bottom;
+ }
+
+ // when child is outside bounds, nudge back inside
+ childLeft = clampDimension(childLeft, childWidth, getWidth());
+ childTop = clampDimension(childTop, childHeight, getHeight());
+
+ final int calloutLeft = target.centerX() - childLeft;
+ updateCallout(calloutState, calloutLeft);
+ layoutChild(child, childLeft, childTop);
+
+ }
+
+ private static int clampDimension(int value, int size, int max) {
+ // when larger than bounds, just center
+ if (size > max) {
+ return (max - size) / 2;
+ }
+
+ // clamp to lower bound
+ value = Math.max(value, 0);
+ // clamp to higher bound
+ value = Math.min(value, max - size);
+
+ return value;
+ }
+
+ private static void layoutChild(View child, int left, int top) {
+ child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
+ }
+
+ /**
+ * Begin animating {@link #getChild()} visible.
+ */
+ public void showChild() {
+ final boolean calloutAbove = mCalloutState == android.R.attr.state_first;
+ final Animation anim = AnimationUtils.loadAnimation(getContext(),
+ calloutAbove ? R.anim.quickcontact_above_enter : R.anim.quickcontact_below_enter);
+ mChild.startAnimation(anim);
+ mChild.setVisibility(View.VISIBLE);
+ }
+
+ /**
+ * Begin animating {@link #getChild()} invisible.
+ */
+ public void hideChild(final Runnable onAnimationEnd) {
+ final boolean calloutAbove = mCalloutState == android.R.attr.state_first;
+ final Animation anim = AnimationUtils.loadAnimation(getContext(),
+ calloutAbove ? R.anim.quickcontact_above_exit : R.anim.quickcontact_below_exit);
+
+ if (onAnimationEnd != null) {
+ anim.setAnimationListener(new AnimationListener() {
+ /** {@inheritDoc} */
+ public void onAnimationStart(Animation animation) {
+ // ignored
+ }
+
+ /** {@inheritDoc} */
+ public void onAnimationRepeat(Animation animation) {
+ // ignored
+ }
+
+ /** {@inheritDoc} */
+ public void onAnimationEnd(Animation animation) {
+ onAnimationEnd.run();
+ }
+ });
+ }
+
+ mChild.startAnimation(anim);
+ mChild.setVisibility(View.INVISIBLE);
+ }
+
+ private View.OnTouchListener mOutsideTouchListener;
+
+ public void setOnOutsideTouchListener(View.OnTouchListener listener) {
+ mOutsideTouchListener = listener;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ // at this point, touch wasn't handled by child view; assume outside
+ if (mOutsideTouchListener != null) {
+ return mOutsideTouchListener.onTouch(this, event);
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
deleted file mode 100644
index 5032386..0000000
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.contacts.quickcontact;
-
-import com.android.contacts.ContactsActivity;
-
-import android.content.ContentUris;
-import android.content.Intent;
-import android.graphics.Rect;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.ContactsContract.QuickContact;
-import android.provider.ContactsContract.RawContacts;
-import android.util.Log;
-
-/**
- * Stub translucent activity that just shows {@link QuickContactWindow} floating
- * above the caller. This temporary hack should eventually be replaced with
- * direct framework support.
- */
-public final class QuickContactActivity extends ContactsActivity
- implements QuickContactWindow.OnDismissListener {
- private static final String TAG = "QuickContactActivity";
-
- static final boolean LOGV = false;
- static final boolean FORCE_CREATE = true;
-
- private QuickContactWindow mQuickContact;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- if (LOGV) Log.d(TAG, "onCreate");
-
- this.onNewIntent(getIntent());
- }
-
- @Override
- public void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- if (LOGV) Log.d(TAG, "onNewIntent");
-
- if (QuickContactWindow.TRACE_LAUNCH) {
- android.os.Debug.startMethodTracing(QuickContactWindow.TRACE_TAG);
- }
-
- if (mQuickContact == null || FORCE_CREATE) {
- if (LOGV) Log.d(TAG, "Preparing window");
- mQuickContact = new QuickContactWindow(this, this);
- }
-
- // Use our local window token for now
- Uri lookupUri = intent.getData();
- // Check to see whether it comes from the old version.
- if (android.provider.Contacts.AUTHORITY.equals(lookupUri.getAuthority())) {
- final long rawContactId = ContentUris.parseId(lookupUri);
- lookupUri = RawContacts.getContactLookupUri(getContentResolver(),
- ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
- }
- final Bundle extras = intent.getExtras();
-
- // Read requested parameters for displaying
- final Rect target = intent.getSourceBounds();
- final int mode = extras.getInt(QuickContact.EXTRA_MODE, QuickContact.MODE_MEDIUM);
- final String[] excludeMimes = extras.getStringArray(QuickContact.EXTRA_EXCLUDE_MIMES);
-
- mQuickContact.show(lookupUri, target, mode, excludeMimes);
- }
-
- /** {@inheritDoc} */
- @Override
- public void onBackPressed() {
- if (LOGV) Log.w(TAG, "Unexpected back captured by stub activity");
- finish();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- if (LOGV) Log.d(TAG, "onPause");
-
- // Dismiss any dialog when pausing
- mQuickContact.dismiss();
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- if (LOGV) Log.d(TAG, "onDestroy");
- }
-
- /** {@inheritDoc} */
- @Override
- public void onDismiss(QuickContactWindow dialog) {
- if (LOGV) Log.d(TAG, "onDismiss");
-
- if (isTaskRoot() && !FORCE_CREATE) {
- // Instead of stopping, simply push this to the back of the stack.
- // This is only done when running at the top of the stack;
- // otherwise, we have been launched by someone else so need to
- // allow the user to go back to the caller.
- moveTaskToBack(false);
- } else {
- finish();
- }
- }
-}
diff --git a/src/com/android/contacts/quickcontact/QuickContactBackgroundDrawable.java b/src/com/android/contacts/quickcontact/QuickContactBackgroundDrawable.java
index 9118480..15311f9 100644
--- a/src/com/android/contacts/quickcontact/QuickContactBackgroundDrawable.java
+++ b/src/com/android/contacts/quickcontact/QuickContactBackgroundDrawable.java
@@ -26,37 +26,43 @@
import android.graphics.drawable.Drawable;
/**
- * Drawable that draws three pictures for the QuickContact-Background. ColorFilter is ignored
+ * Background {@link Drawable} for {@link QuickContactWindow} that draws arrow
+ * centered around requested position.
*/
public class QuickContactBackgroundDrawable extends Drawable {
private Drawable mLeftDrawable;
private Drawable mMiddleDrawable;
private Drawable mRightDrawable;
- private int mRequestedX = Integer.MIN_VALUE;
- private boolean mBoundsSet = false;
- private int mAlpha = -1;
+
private int mBottomOverride = Integer.MIN_VALUE;
+ public QuickContactBackgroundDrawable(Resources res) {
+ mLeftDrawable = res.getDrawable(R.drawable.quickactions_arrow_left_holo_light);
+ mMiddleDrawable = res.getDrawable(R.drawable.quickactions_arrow_middle_holo_light);
+ mRightDrawable = res.getDrawable(R.drawable.quickactions_arrow_right_holo_light);
+ }
+
@Override
public void setAlpha(int alpha) {
- mAlpha = alpha;
- setChildAlpha();
+ mLeftDrawable.setAlpha(alpha);
+ mMiddleDrawable.setAlpha(alpha);
+ mRightDrawable.setAlpha(alpha);
}
/**
- * Overrides the bottom bounds. This is used for the animation when the QuickContact
- * expands/collapses options
+ * Overrides the bottom bounds. This is used for the animation when the
+ * QuickContact expands/collapses options
*/
public void setBottomOverride(int value) {
mBottomOverride = value;
- setChildBounds();
+ onBoundsChange(getBounds());
invalidateSelf();
}
public void clearBottomOverride() {
mBottomOverride = Integer.MIN_VALUE;
+ onBoundsChange(getBounds());
invalidateSelf();
- setChildBounds();
}
public float getBottomOverride() {
@@ -64,7 +70,29 @@
}
@Override
+ public boolean isStateful() {
+ return true;
+ }
+
+ @Override
+ protected boolean onStateChange(int[] state) {
+ super.onStateChange(state);
+ mLeftDrawable.setState(state);
+ mMiddleDrawable.setState(state);
+ mRightDrawable.setState(state);
+ return true;
+ }
+
+ @Override
+ protected boolean onLevelChange(int level) {
+ return true;
+ }
+
+ @Override
public void setColorFilter(ColorFilter cf) {
+ mLeftDrawable.setColorFilter(cf);
+ mMiddleDrawable.setColorFilter(cf);
+ mRightDrawable.setColorFilter(cf);
}
@Override
@@ -72,54 +100,22 @@
return PixelFormat.TRANSLUCENT;
}
- public void configure(Resources resources, boolean arrowUp, int requestedX) {
- mLeftDrawable = resources.getDrawable(arrowUp
- ? R.drawable.quickactions_arrowup_left_holo_light
- : R.drawable.quickactions_arrowdown_left_holo_light);
- mMiddleDrawable = resources.getDrawable(arrowUp
- ? R.drawable.quickactions_arrowup_middle_holo_light
- : R.drawable.quickactions_arrowdown_middle_holo_light);
- mRightDrawable = resources.getDrawable(arrowUp
- ? R.drawable.quickactions_arrowup_right_holo_light
- : R.drawable.quickactions_arrowdown_right_holo_light);
-
- mRequestedX = requestedX;
-
- setChildAlpha();
- setChildBounds();
- }
-
@Override
protected void onBoundsChange(Rect bounds) {
- mBoundsSet = true;
- setChildBounds();
- }
+ final int requestedX = getLevel();
- private void setChildAlpha() {
- if (mAlpha == -1) return;
-
- if (mLeftDrawable != null) mLeftDrawable.setAlpha(mAlpha);
- if (mMiddleDrawable != null) mMiddleDrawable.setAlpha(mAlpha);
- if (mRightDrawable != null) mRightDrawable.setAlpha(mAlpha);
- }
-
- private void setChildBounds() {
- if (mRequestedX == Integer.MIN_VALUE) return;
- if (!mBoundsSet) return;
-
- final Rect bounds = getBounds();
- int middleLeft = mRequestedX - mMiddleDrawable.getIntrinsicWidth() / 2;
- int middleRight = mRequestedX + mMiddleDrawable.getIntrinsicWidth() / 2;
+ int middleLeft = requestedX - mMiddleDrawable.getIntrinsicWidth() / 2;
+ int middleRight = requestedX + mMiddleDrawable.getIntrinsicWidth() / 2;
// ensure left drawable is not smaller than its Intrinsic Width
- final int leftExtra = (middleLeft - bounds.left) - mLeftDrawable.getIntrinsicWidth();
+ final int leftExtra = (middleLeft - bounds.left) - mLeftDrawable.getIntrinsicWidth();
if (leftExtra < 0) {
middleLeft -= leftExtra;
middleRight -= leftExtra;
}
// ensure right drawable is not smaller than its Intrinsic Width
- final int rightExtra = (bounds.right - middleRight) - mRightDrawable.getIntrinsicWidth();
+ final int rightExtra = (bounds.right - middleRight) - mRightDrawable.getIntrinsicWidth();
if (rightExtra < 0) {
middleLeft += rightExtra;
middleRight += rightExtra;
diff --git a/src/com/android/contacts/quickcontact/QuickContactRootLayout.java b/src/com/android/contacts/quickcontact/QuickContactRootLayout.java
deleted file mode 100644
index 007783a..0000000
--- a/src/com/android/contacts/quickcontact/QuickContactRootLayout.java
+++ /dev/null
@@ -1,54 +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.quickcontact;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.widget.LinearLayout;
-
-/**
- * Custom layout for Quick Contact. It intercepts the BACK key and
- * close QC even when the soft keyboard is open.
- */
-public class QuickContactRootLayout extends LinearLayout {
- private Listener mListener;
-
- public QuickContactRootLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public void setListener(Listener value) {
- mListener = value;
- }
-
- /**
- * Intercepts the BACK key event and dismisses QuickContact window.
- */
- @Override
- public boolean dispatchKeyEventPreIme(KeyEvent event) {
- if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
- if (mListener != null) mListener.onBackPressed();
- return true;
- }
- return super.dispatchKeyEventPreIme(event);
- }
-
- public interface Listener {
- void onBackPressed();
- }
-}
diff --git a/src/com/android/contacts/quickcontact/QuickContactWindow.java b/src/com/android/contacts/quickcontact/QuickContactWindow.java
index 063d446..5f4bcc9 100644
--- a/src/com/android/contacts/quickcontact/QuickContactWindow.java
+++ b/src/com/android/contacts/quickcontact/QuickContactWindow.java
@@ -20,17 +20,18 @@
import com.android.contacts.ContactPresenceIconUtil;
import com.android.contacts.ContactSaveService;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType.DataKind;
import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.DataKind;
import com.android.contacts.util.Constants;
import com.android.contacts.util.DataStatus;
import com.android.contacts.util.NotifyingAsyncQueryHandler;
-import com.android.internal.policy.PolicyManager;
import com.google.android.collect.Lists;
+import com.google.common.base.Preconditions;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ContentUris;
import android.content.Context;
@@ -42,6 +43,7 @@
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Handler;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Im;
@@ -55,30 +57,16 @@
import android.provider.ContactsContract.QuickContact;
import android.provider.ContactsContract.RawContacts;
import android.text.TextUtils;
-import android.util.Log;
-import android.view.ActionMode;
-import android.view.ContextThemeWrapper;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
-import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewStub;
-import android.view.ViewTreeObserver.OnGlobalLayoutListener;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityEvent;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.FrameLayout;
-import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
@@ -89,65 +77,44 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
- * Window that shows QuickContact dialog for a specific {@link Contacts#_ID}.
+ * Mostly translucent {@link Activity} that shows QuickContact dialog. It loads
+ * data asynchronously, and then shows a popup with details centered around
+ * {@link Intent#getSourceBounds()}.
*/
-public class QuickContactWindow implements Window.Callback,
+public class QuickContactWindow extends Activity implements
NotifyingAsyncQueryHandler.AsyncQueryListener, View.OnClickListener,
- AbsListView.OnItemClickListener, KeyEvent.Callback, OnGlobalLayoutListener,
- QuickContactRootLayout.Listener {
- private static final String TAG = "QuickContactWindow";
+ AbsListView.OnItemClickListener {
+ private static final String TAG = "QuickContact";
- /**
- * Interface used to allow the person showing a {@link QuickContactWindow} to
- * know when the window has been dismissed.
- */
- public interface OnDismissListener {
- public void onDismiss(QuickContactWindow dialog);
- }
+ private static final boolean TRACE_LAUNCH = false;
+ private static final String TRACE_TAG = "quickcontact";
- private final static int ANIMATION_FADE_IN_TIME = 100;
- private final static int ANIMATION_FADE_OUT_TIME = 100;
- private final static int ANIMATION_EXPAND_TIME = 100;
- private final static int ANIMATION_COLLAPSE_TIME = 100;
-
- private final Context mContext;
- private final LayoutInflater mInflater;
- private final WindowManager mWindowManager;
- private Window mWindow;
- private View mDecor;
- private final Rect mRect = new Rect();
-
- private boolean mDismissed = false;
- private boolean mQuerying = false;
- private boolean mShowing = false;
+ private static final int ANIMATION_FADE_IN_TIME = 100;
+ private static final int ANIMATION_FADE_OUT_TIME = 100;
+ private static final int ANIMATION_EXPAND_TIME = 100;
+ private static final int ANIMATION_COLLAPSE_TIME = 100;
private NotifyingAsyncQueryHandler mHandler;
- private OnDismissListener mDismissListener;
private Uri mLookupUri;
- private Rect mAnchor;
-
- private int mScreenWidth;
- private int mUseableScreenHeight;
- private int mRequestedY;
+ private int mMode;
+ private String[] mExcludeMimes;
private boolean mHasValidSocial = false;
- private int mMode;
- private QuickContactRootLayout mRootView;
+ private FloatingChildLayout mFloatingLayout;
private QuickContactBackgroundDrawable mBackground;
- private View mHeader;
- private HorizontalScrollView mTrackScroll;
- private ViewGroup mTrack;
+ private View mHeader;
+ private ViewGroup mTrack;
private FrameLayout mFooter;
private LinearLayout mFooterDisambig;
private LinearLayout mFooterClearDefaults;
+
private ListView mResolveList;
private CheckableImageView mLastAction;
private CheckBox mSetPrimaryCheckBox;
@@ -159,9 +126,6 @@
*/
private HashMap<String, Action> mDefaultsMap = new HashMap<String, Action>();
- private int mWindowRecycled = 0;
- private int mActionRecycled = 0;
-
/**
* Set of {@link Action} that are associated with the aggregate currently
* displayed by this dialog, represented as a map from {@link String}
@@ -170,14 +134,6 @@
private ActionMultiMap mActions = new ActionMultiMap();
/**
- * Pool of unused {@link CheckableImageView} that have previously been
- * inflated, and are ready to be recycled through {@link #obtainView()}.
- */
- private LinkedList<CheckableImageView> mActionPool = new LinkedList<CheckableImageView>();
-
- private String[] mExcludeMimes;
-
- /**
* {@link #PRECEDING_MIMETYPES} and {@link #FOLLOWING_MIMETYPES} are used to sort MIME-types.
*
* <p>The MIME-types in {@link #PRECEDING_MIMETYPES} appear in the front of the dialog,
@@ -215,82 +171,48 @@
});
private static final int TOKEN_DATA = 1;
- static final boolean TRACE_LAUNCH = false;
- static final String TRACE_TAG = "quickcontact";
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
- /**
- * Prepare a dialog to show in the given {@link Context}.
- */
- public QuickContactWindow(Context context) {
- mContext = new ContextThemeWrapper(context, R.style.QuickContact);
- mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
+ setContentView(R.layout.quickcontact_activity);
- mWindow = PolicyManager.makeNewWindow(mContext);
- mWindow.setCallback(this);
- mWindow.setWindowManager(mWindowManager, null, null);
- mWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED);
+ mBackground = new QuickContactBackgroundDrawable(getResources());
- mWindow.setContentView(R.layout.quickcontact);
+ mFloatingLayout = findTypedViewById(R.id.floating_layout);
+ mFloatingLayout.getChild().setBackgroundDrawable(mBackground);
+ mFloatingLayout.setOnOutsideTouchListener(mOnOutsideTouchListener);
- mRootView = (QuickContactRootLayout)mWindow.findViewById(R.id.root);
- mRootView.setListener(this);
- mRootView.setFocusable(true);
- mRootView.setFocusableInTouchMode(true);
- mRootView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
+ mTrack = findTypedViewById(R.id.quickcontact);
+ mFooter = findTypedViewById(R.id.footer);
+ mFooterDisambig = findTypedViewById(R.id.footer_disambig);
+ mFooterClearDefaults = findTypedViewById(R.id.footer_clear_defaults);
+ mResolveList = findTypedViewById(android.R.id.list);
+ mSetPrimaryCheckBox = findTypedViewById(android.R.id.checkbox);
- mBackground = new QuickContactBackgroundDrawable();
- mRootView.setBackgroundDrawable(mBackground);
+ mDefaultsListView = findTypedViewById(R.id.defaults_list);
- mScreenWidth = mWindowManager.getDefaultDisplay().getWidth();
- // Status bar height
- final int screenMarginBottom = context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.screen_margin_bottom);
- mUseableScreenHeight = mWindowManager.getDefaultDisplay().getHeight() - screenMarginBottom;
+ mClearDefaultsButton = findTypedViewById(R.id.clear_defaults_button);
+ mClearDefaultsButton.setOnClickListener(mOnClearDefaultsClickListener);
- mTrack = (ViewGroup) mWindow.findViewById(R.id.quickcontact);
- mTrackScroll = (HorizontalScrollView) mWindow.findViewById(R.id.scroll);
+ mResolveList.setOnItemClickListener(this);
- mFooter = (FrameLayout) mWindow.findViewById(R.id.footer);
- mFooterDisambig = (LinearLayout) mWindow.findViewById(R.id.footer_disambig);
- mFooterClearDefaults = (LinearLayout) mWindow.findViewById(R.id.footer_clear_defaults);
- mResolveList = (ListView) mWindow.findViewById(android.R.id.list);
- mSetPrimaryCheckBox = (CheckBox) mWindow.findViewById(android.R.id.checkbox);
+ mHandler = new NotifyingAsyncQueryHandler(this, this);
- mDefaultsListView = (ListView) mWindow.findViewById(R.id.defaults_list);
- mClearDefaultsButton = (Button) mWindow.findViewById(R.id.clear_defaults_button);
- mClearDefaultsButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- clearDefaults();
- }
- });
-
- mResolveList.setOnItemClickListener(QuickContactWindow.this);
-
- mHandler = new NotifyingAsyncQueryHandler(mContext, this);
- }
-
- /**
- * Prepare a dialog to show in the given {@link Context}, and notify the
- * given {@link OnDismissListener} each time this dialog is dismissed.
- */
- public QuickContactWindow(Context context, OnDismissListener dismissListener) {
- this(context);
- mDismissListener = dismissListener;
+ show();
}
private View getHeaderView(int mode) {
View header = null;
switch (mode) {
case QuickContact.MODE_SMALL:
- header = mWindow.findViewById(R.id.header_small);
+ header = findViewById(R.id.header_small);
break;
case QuickContact.MODE_MEDIUM:
- header = mWindow.findViewById(R.id.header_medium);
+ header = findViewById(R.id.header_medium);
break;
case QuickContact.MODE_LARGE:
- header = mWindow.findViewById(R.id.header_large);
+ header = findViewById(R.id.header_large);
break;
}
@@ -305,60 +227,52 @@
return header;
}
- /**
- * Start showing a dialog for the given {@link Contacts#_ID} pointing
- * towards the given location.
- */
- public synchronized void show(Uri lookupUri, Rect anchor, int mode, String[] excludeMimes) {
- if (mQuerying || mShowing) {
- Log.w(TAG, "dismissing before showing");
- dismissInternal();
- }
+ private void show() {
- if (TRACE_LAUNCH && !android.os.Debug.isMethodTracingActive()) {
+ if (TRACE_LAUNCH) {
android.os.Debug.startMethodTracing(TRACE_TAG);
}
- // Validate incoming parameters
- final boolean validMode = (mode == QuickContact.MODE_SMALL
- || mode == QuickContact.MODE_MEDIUM || mode == QuickContact.MODE_LARGE);
- if (!validMode) {
- throw new IllegalArgumentException("Invalid mode, expecting MODE_LARGE, "
- + "MODE_MEDIUM, or MODE_SMALL");
+ final Intent intent = getIntent();
+
+ Uri lookupUri = intent.getData();
+
+ // Check to see whether it comes from the old version.
+ if (android.provider.Contacts.AUTHORITY.equals(lookupUri.getAuthority())) {
+ final long rawContactId = ContentUris.parseId(lookupUri);
+ lookupUri = RawContacts.getContactLookupUri(getContentResolver(),
+ ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
}
- if (anchor == null) {
- throw new IllegalArgumentException("Missing anchor rectangle");
+ mLookupUri = Preconditions.checkNotNull(lookupUri, "missing lookupUri");
+
+ // Read requested parameters for displaying
+ final Rect targetScreen = intent.getSourceBounds();
+ Preconditions.checkNotNull(targetScreen, "missing targetScreen");
+ mFloatingLayout.setChildTargetScreen(targetScreen);
+
+ mMode = intent.getIntExtra(QuickContact.EXTRA_MODE, QuickContact.MODE_MEDIUM);
+ mExcludeMimes = intent.getStringArrayExtra(QuickContact.EXTRA_EXCLUDE_MIMES);
+
+ switch (mMode) {
+ case QuickContact.MODE_SMALL:
+ case QuickContact.MODE_MEDIUM:
+ case QuickContact.MODE_LARGE:
+ break;
+ default:
+ throw new IllegalArgumentException("Unexpected mode: " + mMode);
}
- // Prepare header view for requested mode
- mLookupUri = lookupUri;
- mAnchor = new Rect(anchor);
- mMode = mode;
- mExcludeMimes = excludeMimes;
-
- mHeader = getHeaderView(mode);
-
+ // find and prepare correct header view
+ mHeader = getHeaderView(mMode);
setHeaderText(R.id.name, R.string.quickcontact_missing_name);
-
setHeaderText(R.id.status, null);
setHeaderText(R.id.timestamp, null);
-
setHeaderImage(R.id.presence, null);
- resetTrack();
-
- // We need to have a focused view inside the QuickContact window so
- // that the BACK key event can be intercepted
- mRootView.requestFocus();
-
- mHasValidSocial = false;
- mDismissed = false;
- mQuerying = true;
-
// Start background query for data, but only select photo rows when they
// directly match the super-primary PHOTO_ID.
- final Uri dataUri = getDataUri(lookupUri);
+ final Uri dataUri = Uri.withAppendedPath(lookupUri, Contacts.Data.CONTENT_DIRECTORY);
mHandler.cancelOperation(TOKEN_DATA);
// Only request photo data when required by mode
@@ -374,231 +288,85 @@
}
}
- /**
- * Build a {@link Uri} into the {@link Data} table for the requested
- * {@link Contacts#CONTENT_LOOKUP_URI} style {@link Uri}.
- */
- private Uri getDataUri(Uri lookupUri) {
- // TODO: Formalize method of extracting LOOKUP_KEY
- final List<String> path = lookupUri.getPathSegments();
- final boolean validLookup = path.size() >= 3 && "lookup".equals(path.get(1));
- if (!validLookup) {
- // We only accept valid lookup-style Uris
- throw new IllegalArgumentException("Expecting lookup-style Uri");
- } else if (path.size() == 3) {
- // No direct _ID provided, so force a lookup
- lookupUri = Contacts.lookupContact(mContext.getContentResolver(), lookupUri);
- }
-
- final long contactId = ContentUris.parseId(lookupUri);
- return Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId),
- Contacts.Data.CONTENT_DIRECTORY);
+ @SuppressWarnings("unchecked")
+ private <T> T findTypedViewById(int id) {
+ return (T) super.findViewById(id);
}
- /**
- * Creates and configures the background resource
- */
- private void configureBackground(boolean arrowUp, int requestedX) {
- mBackground.configure(mContext.getResources(), arrowUp, requestedX);
+ private View.OnTouchListener mOnOutsideTouchListener = new View.OnTouchListener() {
+ /** {@inheritDoc} */
+ public boolean onTouch(View v, MotionEvent event) {
+ hide(true);
+ return true;
+ }
+ };
+
+ private View.OnClickListener mOnClearDefaultsClickListener = new View.OnClickListener() {
+ /** {@inheritDoc} */
+ public void onClick(View v) {
+ clearDefaults();
+ }
+ };
+
+ private void hide(boolean withAnimation) {
+ // cancel any pending queries
+ mHandler.cancelOperation(TOKEN_DATA);
+
+ if (withAnimation) {
+ mFloatingLayout.hideChild(new Runnable() {
+ /** {@inheritDoc} */
+ public void run() {
+ finish();
+ }
+ });
+ } else {
+ mFloatingLayout.hideChild(null);
+ finish();
+ }
}
- /**
- * Actual internal method to show this dialog. Called only by
- * {@link #considerShowing()} when all data requirements have been met.
- */
- private void showInternal() {
- mDecor = mWindow.getDecorView();
- mDecor.getViewTreeObserver().addOnGlobalLayoutListener(this);
- WindowManager.LayoutParams layoutParams = mWindow.getAttributes();
-
- layoutParams.width = mContext.getResources().getDimensionPixelSize(
- R.dimen.quick_contact_width);
- layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
-
- // Try to left align with the anchor control
- if (mAnchor.left + layoutParams.width <= mScreenWidth) {
- layoutParams.x = mAnchor.left;
- } else {
- // Not enough space. Try to right align to the anchor
- if (mAnchor.right - layoutParams.width >= 0) {
- layoutParams.x = mAnchor.right - layoutParams.width;
- } else {
- // Also not enough space. Use the whole screen width available
- layoutParams.x = 0;
- layoutParams.width = mScreenWidth;
- }
- }
-
- // Force layout measuring pass so we have baseline numbers
- mDecor.measure(layoutParams.width, layoutParams.height);
- final int blockHeight = mDecor.getMeasuredHeight();
-
- layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
-
- if (mUseableScreenHeight - mAnchor.bottom > blockHeight) {
- // Show downwards callout when enough room, aligning block top with bottom of
- // anchor area, and adjusting to inset arrow.
- configureBackground(true, mAnchor.centerX() - layoutParams.x);
- layoutParams.y = mAnchor.bottom;
- layoutParams.windowAnimations = R.style.QuickContactBelowAnimation;
- } else {
- // Show upwards callout, aligning bottom block
- // edge with top of anchor area, and adjusting to inset arrow.
- configureBackground(false, mAnchor.centerX() - layoutParams.x);
- layoutParams.y = mAnchor.top - blockHeight;
- layoutParams.windowAnimations = R.style.QuickContactAboveAnimation;
- }
-
- layoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
-
- mRequestedY = layoutParams.y;
- mWindowManager.addView(mDecor, layoutParams);
- mShowing = true;
- mQuerying = false;
- mDismissed = false;
-
- if (TRACE_LAUNCH) {
- android.os.Debug.stopMethodTracing();
- Log.d(TAG, "Window recycled " + mWindowRecycled + " times, chiclets "
- + mActionRecycled + " times");
- }
+ @Override
+ public void onBackPressed() {
+ hide(true);
}
/** {@inheritDoc} */
- @Override
- public void onGlobalLayout() {
- layoutInScreen();
- }
+ public synchronized void onQueryComplete(int token, Object cookie, Cursor cursor) {
+ try {
+ if (isFinishing()) {
+ hide(false);
+ return;
+ } else if (cursor == null || cursor.getCount() == 0) {
+ Toast.makeText(this, R.string.invalidContactMessage, Toast.LENGTH_LONG).show();
+ hide(false);
+ return;
+ }
- /**
- * Adjust vertical {@link WindowManager.LayoutParams} to fit window as best
- * as possible, shifting up to display content as needed.
- */
- private void layoutInScreen() {
- if (!mShowing) return;
+ bindData(cursor);
- final WindowManager.LayoutParams l = mWindow.getAttributes();
- final int originalY = l.y;
-
- final int blockHeight = mDecor.getHeight();
-
- l.y = mRequestedY;
- if (mRequestedY + blockHeight > mUseableScreenHeight) {
- // Shift up from bottom when overflowing
- l.y = mUseableScreenHeight - blockHeight;
- }
-
- if (originalY != l.y) {
- // Only update when value is changed
- mWindow.setAttributes(l);
- }
- }
-
- /**
- * Dismiss this dialog if showing.
- */
- public synchronized void dismiss() {
- // Notify any listeners that we've been dismissed
- if (mDismissListener != null) {
- mDismissListener.onDismiss(this);
- }
-
- dismissInternal();
- }
-
- private void dismissInternal() {
- // Remove any attached window decor for recycling
- boolean hadDecor = mDecor != null;
- if (hadDecor) {
- mWindowManager.removeView(mDecor);
- mWindowRecycled++;
- mDecor.getViewTreeObserver().removeGlobalOnLayoutListener(this);
- mDecor = null;
- mWindow.closeAllPanels();
- }
- mShowing = false;
- mDismissed = true;
-
- // Cancel any pending queries
- mHandler.cancelOperation(TOKEN_DATA);
- mQuerying = false;
-
- // Completely hide header and reset track
- mHeader.setVisibility(View.GONE);
- resetTrack();
- }
-
- /**
- * Reset track to initial state, recycling any chiclets.
- */
- private void resetTrack() {
- // Clear background height-animation override
- mBackground.clearBottomOverride();
-
- // Release reference to last chiclet
- mLastAction = null;
-
- // Clear track actions and scroll to hard left
- mActions.clear();
-
- // Recycle any chiclets in use
- for (int i = mTrack.getChildCount() - 1; i >= 0; i--) {
- releaseView((CheckableImageView)mTrack.getChildAt(i));
- mTrack.removeViewAt(i);
- }
-
- mTrackScroll.fullScroll(View.FOCUS_LEFT);
-
- // Clear any primary requests
- mSetPrimaryCheckBox.setChecked(false);
-
- setNewActionViewChecked(null);
- mFooter.setVisibility(View.GONE);
- }
-
- /**
- * Consider showing this window, which will only call through to
- * {@link #showInternal()} when all data items are present.
- */
- private void considerShowing() {
- if (!mShowing && !mDismissed) {
if (mMode == QuickContact.MODE_MEDIUM && !mHasValidSocial) {
// Missing valid social, swap medium for small header
mHeader.setVisibility(View.GONE);
mHeader = getHeaderView(QuickContact.MODE_SMALL);
}
- // All queries have returned, pull curtain
- showInternal();
+ if (TRACE_LAUNCH) {
+ android.os.Debug.stopMethodTracing();
+ }
+
+ // data bound and ready, pull curtain to show
+ mFloatingLayout.showChild();
+
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
}
- /** {@inheritDoc} */
- @Override
- public synchronized void onQueryComplete(int token, Object cookie, Cursor cursor) {
- // Bail early when query is stale
- if (cookie != mLookupUri) return;
-
- if (cursor == null) {
- // Problem while running query, so bail without showing
- Log.w(TAG, "Missing cursor for token=" + token);
- this.dismiss();
- return;
- }
-
- handleData(cursor);
-
- if (!cursor.isClosed()) {
- cursor.close();
- }
-
- considerShowing();
- }
-
/** Assign this string to the view, if found in {@link #mHeader}. */
private void setHeaderText(int id, int resId) {
- setHeaderText(id, mContext.getResources().getText(resId));
+ setHeaderText(id, getText(resId));
}
/** Assign this string to the view, if found in {@link #mHeader}. */
@@ -636,26 +404,22 @@
/**
* Handle the result from the {@link #TOKEN_DATA} query.
*/
- private void handleData(Cursor cursor) {
- final ResolveCache cache = ResolveCache.getInstance(mContext.getPackageManager());
- if (cursor == null) return;
- if (cursor.getCount() == 0) {
- Toast.makeText(mContext, R.string.invalidContactMessage, Toast.LENGTH_LONG).show();
- dismiss();
- return;
- }
+ private void bindData(Cursor cursor) {
+ final ResolveCache cache = ResolveCache.getInstance(this);
+ final Context context = this;
if (!isMimeExcluded(Contacts.CONTENT_ITEM_TYPE)) {
// Add the profile shortcut action
- final Action action = new ProfileAction(mContext, mLookupUri);
+ final Action action = new ProfileAction(context, mLookupUri);
mActions.put(Contacts.CONTENT_ITEM_TYPE, action);
}
mDefaultsMap.clear();
final DataStatus status = new DataStatus();
- final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
- final ImageView photoView = (ImageView)mHeader.findViewById(R.id.photo);
+ final AccountTypeManager accountTypes = AccountTypeManager.getInstance(
+ context.getApplicationContext());
+ final ImageView photoView = (ImageView) mHeader.findViewById(R.id.photo);
Bitmap photoBitmap = null;
while (cursor.moveToNext()) {
@@ -687,7 +451,7 @@
// Build an action for this data entry, find a mapping to a UI
// element, build its summary from the cursor, and collect it
// along with all others of this MIME-type.
- final Action action = new DataAction(mContext, mimeType, kind, dataId, cursor);
+ final Action action = new DataAction(context, mimeType, kind, dataId, cursor);
final boolean wasAdded = considerAdd(action, cache);
if (wasAdded) {
// Remember the default
@@ -699,7 +463,7 @@
// If phone number, also insert as text message action
if (Phone.CONTENT_ITEM_TYPE.equals(mimeType) && kind != null) {
- final DataAction action = new DataAction(mContext, Constants.MIME_TYPE_SMS_ADDRESS,
+ final DataAction action = new DataAction(context, Constants.MIME_TYPE_SMS_ADDRESS,
kind, dataId, cursor);
considerAdd(action, cache);
}
@@ -712,7 +476,7 @@
final DataKind imKind = accountTypes.getKindOrFallback(accountType,
Im.CONTENT_ITEM_TYPE);
if (imKind != null) {
- final DataAction action = new DataAction(mContext, Im.CONTENT_ITEM_TYPE, imKind,
+ final DataAction action = new DataAction(context, Im.CONTENT_ITEM_TYPE, imKind,
dataId, cursor);
considerAdd(action, cache);
isIm = true;
@@ -725,7 +489,7 @@
final DataKind imKind = accountTypes.getKindOrFallback(accountType,
Im.CONTENT_ITEM_TYPE);
if (imKind != null) {
- final DataAction chatAction = new DataAction(mContext,
+ final DataAction chatAction = new DataAction(context,
Constants.MIME_TYPE_VIDEO_CHAT, imKind, dataId, cursor);
considerAdd(chatAction, cache);
}
@@ -733,7 +497,22 @@
}
}
- if (mDefaultsMap.size() != 0) {
+ // Collapse Action Lists (remove e.g. duplicate e-mail addresses from different sources)
+ for (ArrayList<Action> actionChildren : mActions.values()) {
+ Collapser.collapseList(actionChildren);
+ }
+
+ // Make sure that we only display the "clear default" action if there
+ // are actually several items to chose from
+ boolean shouldDisplayClearDefaults = false;
+ for (String mimetype : mDefaultsMap.keySet()) {
+ if (mActions.get(mimetype).size() > 1) {
+ shouldDisplayClearDefaults = true;
+ break;
+ }
+ }
+
+ if (shouldDisplayClearDefaults) {
final Action action = new ClearDefaultsAction();
mActions.put(action.getMimeType(), action);
}
@@ -744,7 +523,7 @@
final int presence = cursor.getInt(DataQuery.CONTACT_PRESENCE);
final int chatCapability = cursor.getInt(DataQuery.CONTACT_CHAT_CAPABILITY);
final Drawable statusIcon = ContactPresenceIconUtil.getChatCapabilityIcon(
- mContext, presence, chatCapability);
+ context, presence, chatCapability);
setHeaderText(R.id.name, name);
setHeaderImage(R.id.presence, statusIcon);
@@ -760,7 +539,7 @@
if (mHasValidSocial && mMode != QuickContact.MODE_SMALL) {
// Update status when valid was found
setHeaderText(R.id.status, status.getStatus());
- setHeaderText(R.id.timestamp, status.getTimestampLabel(mContext));
+ setHeaderText(R.id.timestamp, status.getTimestampLabel(context));
}
// Turn our list of actions into UI elements
@@ -774,7 +553,7 @@
for (String mimeType : PRECEDING_MIMETYPES) {
if (containedTypes.contains(mimeType)) {
hasData = true;
- mTrack.addView(inflateAction(mimeType, cache));
+ mTrack.addView(inflateAction(mimeType, cache, mTrack));
containedTypes.remove(mimeType);
}
}
@@ -786,7 +565,7 @@
for (String mimeType : FOLLOWING_MIMETYPES) {
if (containedTypes.contains(mimeType)) {
hasData = true;
- mTrack.addView(inflateAction(mimeType, cache));
+ mTrack.addView(inflateAction(mimeType, cache, mTrack));
containedTypes.remove(mimeType);
}
}
@@ -795,9 +574,11 @@
if (containedTypes.contains(ClearDefaultsAction.PSEUDO_MIME_TYPE)) {
final ClearDefaultsAction action = (ClearDefaultsAction) mActions.get(
ClearDefaultsAction.PSEUDO_MIME_TYPE).get(0);
- final CheckableImageView view = obtainView();
+ final CheckableImageView view = (CheckableImageView) getLayoutInflater().inflate(
+ R.layout.quickcontact_item, mTrack, false);
+
view.setChecked(false);
- final String description = mContext.getResources().getString(
+ final String description = context.getResources().getString(
R.string.quickcontact_clear_defaults_description);
view.setContentDescription(description);
view.setImageResource(R.drawable.ic_menu_settings_holo_light);
@@ -813,12 +594,13 @@
if (remainingTypes.length > 0) hasData = true;
Arrays.sort(remainingTypes);
for (String mimeType : remainingTypes) {
- mTrack.addView(inflateAction(mimeType, cache), index++);
+ mTrack.addView(inflateAction(mimeType, cache, mTrack), index++);
}
if (!hasData) {
// When there is no data to display, add a TextView to show the user there's no data
- View view = mInflater.inflate(R.layout.quickcontact_item_nodata, mTrack, false);
+ View view = getLayoutInflater().inflate(
+ R.layout.quickcontact_item_nodata, mTrack, false);
mTrack.addView(view, index++);
}
}
@@ -827,7 +609,9 @@
* Clears the defaults currently set on the Contact
*/
private void clearDefaults() {
+ final Context context = this;
final Set<String> mimeTypesKeySet = mDefaultsMap.keySet();
+
// Copy to array so that we can modify the HashMap below
final String[] mimeTypes = new String[mimeTypesKeySet.size()];
mimeTypesKeySet.toArray(mimeTypes);
@@ -835,9 +619,9 @@
// Send clear default Intents, one by one
for (String mimeType : mimeTypes) {
final Action action = mDefaultsMap.get(mimeType);
- final Intent intent =
- ContactSaveService.createClearPrimaryIntent(mContext, action.getDataId());
- mContext.startService(intent);
+ final Intent intent = ContactSaveService.createClearPrimaryIntent(
+ context, action.getDataId());
+ context.startService(intent);
mDefaultsMap.remove(mimeType);
}
@@ -848,7 +632,6 @@
for (int i = mTrack.getChildCount() - 1; i >= 0; i--) {
final CheckableImageView button = (CheckableImageView) mTrack.getChildAt(i);
if (button.getTag() instanceof ClearDefaultsAction) {
- releaseView(button);
mTrack.removeViewAt(i);
break;
}
@@ -872,41 +655,15 @@
}
/**
- * Obtain a new {@link CheckableImageView} for a new chiclet, either by
- * recycling one from {@link #mActionPool}, or by inflating a new one. When
- * finished, use {@link #releaseView(CheckableImageView)} to return back into the pool for
- * later recycling.
- */
- private synchronized CheckableImageView obtainView() {
- CheckableImageView view = mActionPool.poll();
- if (view == null || QuickContactActivity.FORCE_CREATE) {
- view = (CheckableImageView) mInflater.inflate(R.layout.quickcontact_item, mTrack,
- false);
- }
- return view;
- }
-
- /**
- * Return the given {@link CheckableImageView} into our internal pool for
- * possible recycling during another pass.
- */
- private synchronized void releaseView(CheckableImageView view) {
- mActionPool.offer(view);
- mActionRecycled++;
- }
-
- /**
* Inflate the in-track view for the action of the given MIME-type, collapsing duplicate values.
* Will use the icon provided by the {@link DataKind}.
*/
- private View inflateAction(String mimeType, ResolveCache resolveCache) {
- final CheckableImageView view = obtainView();
+ private View inflateAction(String mimeType, ResolveCache resolveCache, ViewGroup root) {
+ final CheckableImageView view = (CheckableImageView) getLayoutInflater().inflate(
+ R.layout.quickcontact_item, root, false);
// Add direct intent if single child, otherwise flag for multiple
List<Action> children = mActions.get(mimeType);
- if (children.size() > 1) {
- Collapser.collapseList(children);
- }
view.setTag(mimeType);
final Action firstInfo = children.get(0);
@@ -983,6 +740,13 @@
expandAnimator.setDuration(ANIMATION_EXPAND_TIME);
expandAnimator.start();
+ expandAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mBackground.clearBottomOverride();
+ }
+ });
+
final ObjectAnimator fadeInAnimator = ObjectAnimator.ofFloat(mFooter,
"alpha", 0.0f, 1.0f);
fadeInAnimator.setDuration(ANIMATION_FADE_IN_TIME);
@@ -995,9 +759,12 @@
/** {@inheritDoc} */
@Override
public void onClick(View view) {
+ final Context context = this;
+
final boolean isActionView = (view instanceof CheckableImageView);
final CheckableImageView actionView = isActionView ? (CheckableImageView)view : null;
final Object tag = view.getTag();
+
if (tag instanceof ClearDefaultsAction) {
// Do nothing if already open
if (actionView == mLastAction) return;
@@ -1038,29 +805,28 @@
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- final View result = convertView != null ? convertView :
- mInflater.inflate(R.layout.quickcontact_default_item,
- parent, false);
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(
+ R.layout.quickcontact_default_item, parent, false);
+ }
+
// Set action title based on summary value
final Action defaultAction = actions[position];
- TextView text1 = (TextView)result.findViewById(android.R.id.text1);
- TextView text2 = (TextView)result.findViewById(android.R.id.text2);
+ final TextView text1 = (TextView) convertView.findViewById(
+ android.R.id.text1);
+ final TextView text2 = (TextView) convertView.findViewById(
+ android.R.id.text2);
text1.setText(defaultAction.getHeader());
text2.setText(defaultAction.getBody());
- result.setTag(defaultAction);
- return result;
+ convertView.setTag(defaultAction);
+ return convertView;
}
});
animateExpand(true);
- // Make sure we resize to make room for ListView
- if (mDecor != null) {
- mDecor.forceLayout();
- mDecor.invalidate();
- }
}
};
if (mFooter.getVisibility() == View.VISIBLE) {
@@ -1109,24 +875,24 @@
public void run() {
// Incoming tag is concrete intent, so try launching
try {
- mContext.startActivity(action.getIntent());
+ context.startActivity(action.getIntent());
} catch (ActivityNotFoundException e) {
- Toast.makeText(mContext, R.string.quickcontact_missing_app,
+ Toast.makeText(context, R.string.quickcontact_missing_app,
Toast.LENGTH_SHORT).show();
}
// Hide the resolution list, if present
setNewActionViewChecked(null);
- dismiss();
- mFooter.setVisibility(View.GONE);
// Set default?
final long dataId = action.getDataId();
if (makePrimary && dataId != -1) {
Intent serviceIntent = ContactSaveService.createSetSuperPrimaryIntent(
- mContext, dataId);
- mContext.startService(serviceIntent);
+ context, dataId);
+ context.startService(serviceIntent);
}
+
+ hide(false);
}
};
if (isActionView && mFooter.getVisibility() == View.VISIBLE) {
@@ -1171,31 +937,31 @@
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- final View result = convertView != null ? convertView :
- mInflater.inflate(R.layout.quickcontact_resolve_item,
- parent, false);
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(
+ R.layout.quickcontact_resolve_item, parent, false);
+ }
+
// Set action title based on summary value
final Action listAction = actionList.get(position);
- TextView text1 = (TextView)result.findViewById(android.R.id.text1);
- TextView text2 = (TextView)result.findViewById(android.R.id.text2);
+ final TextView text1 = (TextView) convertView.findViewById(
+ android.R.id.text1);
+ final TextView text2 = (TextView) convertView.findViewById(
+ android.R.id.text2);
text1.setText(listAction.getHeader());
text2.setText(listAction.getBody());
- result.setTag(listAction);
- return result;
+ convertView.setTag(listAction);
+ return convertView;
}
});
animateExpand(false);
- // Make sure we resize to make room for ListView
- if (mDecor != null) {
- mDecor.forceLayout();
- mDecor.invalidate();
- }
}
};
+
if (mFooter.getVisibility() == View.VISIBLE) {
// If the expansion list is currently opened, animate its collapse and then
// execute the target app
@@ -1206,185 +972,6 @@
}
}
- @Override
- public void onBackPressed() {
- dismiss();
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (mWindow.superDispatchKeyEvent(event)) {
- return true;
- }
- return event.dispatch(this, mDecor != null
- ? mDecor.getKeyDispatcherState() : null, this);
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- event.startTracking();
- return true;
- }
-
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
- && !event.isCanceled()) {
- onBackPressed();
- return true;
- }
-
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean onKeyLongPress(int keyCode, KeyEvent event) {
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
- return false;
- }
-
- /** {@inheritDoc} */
- public boolean dispatchKeyShortcutEvent(KeyEvent event) {
- return mWindow.superDispatchKeyShortcutEvent(event);
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- // TODO: make this window accessible
- return false;
- }
-
- /**
- * Detect if the given {@link MotionEvent} is outside the boundaries of this
- * window, which usually means we should dismiss.
- */
- protected void detectEventOutside(MotionEvent event) {
- if (event.getAction() == MotionEvent.ACTION_DOWN && mDecor != null) {
- // Only try detecting outside events on down-press
- mDecor.getHitRect(mRect);
- final int x = (int)event.getX();
- final int y = (int)event.getY();
- if (!mRect.contains(x, y)) {
- event.setAction(MotionEvent.ACTION_OUTSIDE);
- }
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean dispatchTouchEvent(MotionEvent event) {
- detectEventOutside(event);
- if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
- dismiss();
- return true;
- }
- return mWindow.superDispatchTouchEvent(event);
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean dispatchTrackballEvent(MotionEvent event) {
- return mWindow.superDispatchTrackballEvent(event);
- }
-
- /** {@inheritDoc} */
- @Override
- public void onContentChanged() {
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean onCreatePanelMenu(int featureId, Menu menu) {
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public View onCreatePanelView(int featureId) {
- return null;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean onMenuItemSelected(int featureId, MenuItem item) {
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean onMenuOpened(int featureId, Menu menu) {
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public void onPanelClosed(int featureId, Menu menu) {
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean onPreparePanel(int featureId, View view, Menu menu) {
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean onSearchRequested() {
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams attrs) {
- if (mDecor != null) {
- mWindowManager.updateViewLayout(mDecor, attrs);
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public void onWindowFocusChanged(boolean hasFocus) {
- }
-
- /** {@inheritDoc} */
- @Override
- public void onAttachedToWindow() {
- // No actions
- }
-
- /** {@inheritDoc} */
- @Override
- public void onDetachedFromWindow() {
- // No actions
- }
-
- /** {@inheritDoc} */
- @Override
- public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
- return null;
- }
-
- @Override
- public void onActionModeStarted(ActionMode mode) {
- }
-
- @Override
- public void onActionModeFinished(ActionMode mode) {
- }
private interface DataQuery {
final String[] PROJECTION = new String[] {
diff --git a/src/com/android/contacts/quickcontact/ResolveCache.java b/src/com/android/contacts/quickcontact/ResolveCache.java
index 5d84253..2b9e92f 100644
--- a/src/com/android/contacts/quickcontact/ResolveCache.java
+++ b/src/com/android/contacts/quickcontact/ResolveCache.java
@@ -16,14 +16,17 @@
package com.android.contacts.quickcontact;
+import com.android.contacts.util.PhoneCapabilityTester;
import com.google.android.collect.Sets;
+import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
+import android.provider.ContactsContract.CommonDataKinds.SipAddress;
import android.text.TextUtils;
import java.lang.ref.SoftReference;
@@ -51,6 +54,7 @@
"com.android.phone",
"com.android.browser");
+ private final Context mContext;
private final PackageManager mPackageManager;
private static ResolveCache sInstance;
@@ -59,9 +63,9 @@
* Returns an instance of the ResolveCache. Only one internal instance is kept, so
* the argument packageManagers is ignored for all but the first call
*/
- public synchronized static ResolveCache getInstance(PackageManager packageManager) {
+ public synchronized static ResolveCache getInstance(Context context) {
if (sInstance == null) {
- return sInstance = new ResolveCache(packageManager);
+ return sInstance = new ResolveCache(context.getApplicationContext());
}
return sInstance;
}
@@ -81,8 +85,10 @@
private HashMap<String, Entry> mCache = new HashMap<String, Entry>();
- private ResolveCache(PackageManager packageManager) {
- mPackageManager = packageManager;
+
+ private ResolveCache(Context context) {
+ mContext = context;
+ mPackageManager = context.getPackageManager();
}
/**
@@ -95,7 +101,12 @@
if (entry != null) return entry;
entry = new Entry();
- final Intent intent = action.getIntent();
+ Intent intent = action.getIntent();
+ if (SipAddress.CONTENT_ITEM_TYPE.equals(mimeType)
+ && !PhoneCapabilityTester.isSipPhone(mContext)) {
+ intent = null;
+ }
+
if (intent != null) {
final List<ResolveInfo> matches = mPackageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
diff --git a/src/com/android/contacts/socialwidget/SocialWidgetConfigureActivity.java b/src/com/android/contacts/socialwidget/SocialWidgetConfigureActivity.java
index 4201cee..98812d9 100644
--- a/src/com/android/contacts/socialwidget/SocialWidgetConfigureActivity.java
+++ b/src/com/android/contacts/socialwidget/SocialWidgetConfigureActivity.java
@@ -51,7 +51,7 @@
// Update the widget
SocialWidgetProvider.loadWidgetData(
- context, AppWidgetManager.getInstance(this), widgetId);
+ context, AppWidgetManager.getInstance(this), widgetId, true);
// Return OK so that the system won't remove the widget
final Intent resultValue = new Intent();
diff --git a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
index 0330c89..92118c0 100644
--- a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
+++ b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
@@ -19,10 +19,12 @@
import com.android.contacts.ContactLoader;
import com.android.contacts.R;
import com.android.contacts.util.ContactBadgeUtil;
+import com.android.contacts.util.DataStatus;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
+import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
@@ -30,6 +32,7 @@
import android.graphics.BitmapFactory;
import android.graphics.Typeface;
import android.net.Uri;
+import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.QuickContact;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
@@ -40,6 +43,8 @@
import android.view.View;
import android.widget.RemoteViews;
+import java.util.HashMap;
+
public class SocialWidgetProvider extends AppWidgetProvider {
private static final String TAG = "SocialWidgetProvider";
@@ -58,7 +63,7 @@
}
for (int appWidgetId : appWidgetIds) {
- loadWidgetData(context, appWidgetManager, appWidgetId);
+ loadWidgetData(context, appWidgetManager, appWidgetId, false);
}
}
@@ -75,41 +80,46 @@
SocialWidgetSettings.getInstance().remove(context, appWidgetIds);
}
- public static void loadWidgetData(
- final Context context, final AppWidgetManager appWidgetManager, final int widgetId) {
- final ContactLoader previousLoader = sLoaders.get(widgetId);
+ public static void loadWidgetData(final Context context,
+ final AppWidgetManager appWidgetManager, final int widgetId, boolean forceLoad) {
+ ContactLoader previousLoader = sLoaders.get(widgetId);
+
+ if (previousLoader != null && !forceLoad) {
+ previousLoader.startLoading();
+ return;
+ }
if (previousLoader != null) {
- previousLoader.startLoading();
- } else {
- // Show that we are loading
- final RemoteViews loadingViews =
- new RemoteViews(context.getPackageName(), R.layout.social_widget);
- loadingViews.setTextViewText(R.id.name,
- context.getString(R.string.social_widget_loading));
- loadingViews.setViewVisibility(R.id.name, View.VISIBLE);
- loadingViews.setViewVisibility(R.id.name_and_snippet, View.GONE);
- appWidgetManager.updateAppWidget(widgetId, loadingViews);
-
- // Load
- final Uri contactUri =
- SocialWidgetSettings.getInstance().getContactUri(context, widgetId);
- if (contactUri == null) {
- // Not yet set-up (this can happen while the Configuration activity is visible)
- return;
- }
- final ContactLoader contactLoader = new ContactLoader(context, contactUri);
- contactLoader.registerListener(0,
- new ContactLoader.OnLoadCompleteListener<ContactLoader.Result>() {
- @Override
- public void onLoadComplete(Loader<ContactLoader.Result> loader,
- ContactLoader.Result contactData) {
- bindRemoteViews(context, widgetId, appWidgetManager, contactData);
- }
- });
- contactLoader.startLoading();
- sLoaders.append(widgetId, contactLoader);
+ previousLoader.reset();
}
+
+ // Show that we are loading
+ final RemoteViews loadingViews =
+ new RemoteViews(context.getPackageName(), R.layout.social_widget);
+ loadingViews.setTextViewText(R.id.name,
+ context.getString(R.string.social_widget_loading));
+ loadingViews.setViewVisibility(R.id.name, View.VISIBLE);
+ loadingViews.setViewVisibility(R.id.name_and_snippet, View.GONE);
+ appWidgetManager.updateAppWidget(widgetId, loadingViews);
+
+ // Load
+ final Uri contactUri =
+ SocialWidgetSettings.getInstance().getContactUri(context, widgetId);
+ if (contactUri == null) {
+ // Not yet set-up (this can happen while the Configuration activity is visible)
+ return;
+ }
+ final ContactLoader contactLoader = new ContactLoader(context, contactUri);
+ contactLoader.registerListener(0,
+ new ContactLoader.OnLoadCompleteListener<ContactLoader.Result>() {
+ @Override
+ public void onLoadComplete(Loader<ContactLoader.Result> loader,
+ ContactLoader.Result contactData) {
+ bindRemoteViews(context, widgetId, appWidgetManager, contactData);
+ }
+ });
+ contactLoader.startLoading();
+ sLoaders.append(widgetId, contactLoader);
}
private static void bindRemoteViews(final Context context, final int widgetId,
@@ -122,13 +132,10 @@
if (contactData == ContactLoader.Result.ERROR ||
contactData == ContactLoader.Result.NOT_FOUND) {
setDisplayNameAndSnippet(context, views,
- context.getString(R.string.invalidContactMessage), null, null);
+ context.getString(R.string.invalidContactMessage), null, null, null);
setPhoto(views, ContactBadgeUtil.loadPlaceholderPhoto(context));
setStatusAttribution(views, null);
} else {
- setDisplayNameAndSnippet(context, views, contactData.getDisplayName(),
- contactData.getPhoneticName(), contactData.getSocialSnippet());
-
byte[] photo = contactData.getPhotoBinaryData();
setPhoto(views, photo != null
? BitmapFactory.decodeByteArray(photo, 0, photo.length)
@@ -148,6 +155,9 @@
final PendingIntent pendingIntent = PendingIntent.getActivity(context,
0, intent, 0);
views.setOnClickPendingIntent(R.id.border, pendingIntent);
+
+ setDisplayNameAndSnippet(context, views, contactData.getDisplayName(),
+ contactData.getPhoneticName(), contactData.getStatuses(), pendingIntent);
}
// Configure UI
@@ -164,7 +174,7 @@
*/
private static void setDisplayNameAndSnippet(Context context, RemoteViews views,
CharSequence displayName, CharSequence phoneticName,
- CharSequence snippet) {
+ HashMap<Long, DataStatus> statuses, PendingIntent defaultIntent) {
SpannableStringBuilder sb = new SpannableStringBuilder();
CharSequence name = displayName;
@@ -180,20 +190,41 @@
sb.setSpan(sizeSpan, 0, name.length(), 0);
sb.setSpan(styleSpan, 0, name.length(), 0);
- if (TextUtils.isEmpty(snippet)) {
+ long latestStatusId = 0;
+ DataStatus latestStatus = null;
+ if (statuses != null) {
+ for (HashMap.Entry<Long, DataStatus> entry : statuses.entrySet()) {
+ DataStatus status = entry.getValue();
+ if (!TextUtils.isEmpty(status.getStatus())
+ && (latestStatus == null
+ || latestStatus.getTimestamp() < status.getTimestamp())) {
+ latestStatusId = entry.getKey();
+ latestStatus = status;
+ }
+ }
+ }
+
+ if (latestStatus == null) {
views.setTextViewText(R.id.name, sb);
views.setViewVisibility(R.id.name, View.VISIBLE);
views.setViewVisibility(R.id.name_and_snippet, View.GONE);
+ views.setOnClickPendingIntent(R.id.widget_container, defaultIntent);
} else {
- if (snippet.length() <= SHORT_SNIPPET_LENGTH) {
+ CharSequence status = latestStatus.getStatus();
+ if (status.length() <= SHORT_SNIPPET_LENGTH) {
sb.append("\n");
} else {
sb.append(" ");
}
- sb.append(snippet);
+ sb.append(status);
views.setTextViewText(R.id.name_and_snippet, sb);
views.setViewVisibility(R.id.name, View.GONE);
views.setViewVisibility(R.id.name_and_snippet, View.VISIBLE);
+ final Intent intent = new Intent(Intent.ACTION_VIEW,
+ ContentUris.withAppendedId(Data.CONTENT_URI, latestStatusId));
+
+ views.setOnClickPendingIntent(R.id.name_and_snippet_container,
+ PendingIntent.getActivity(context, 0, intent, 0));
}
}
diff --git a/src/com/android/contacts/util/AccountsListAdapter.java b/src/com/android/contacts/util/AccountsListAdapter.java
index 8dbfc8d..97a9f84 100644
--- a/src/com/android/contacts/util/AccountsListAdapter.java
+++ b/src/com/android/contacts/util/AccountsListAdapter.java
@@ -60,7 +60,9 @@
final AccountType accountType = mAccountTypes.getAccountType(account.type);
text1.setText(account.name);
- text2.setText(accountType.getDisplayLabel(mContext));
+ if (text2 != null) {
+ text2.setText(accountType.getDisplayLabel(mContext));
+ }
icon.setImageDrawable(accountType.getDisplayIcon(mContext));
return resultView;
diff --git a/src/com/android/contacts/util/DataStatus.java b/src/com/android/contacts/util/DataStatus.java
index ec3c1e5..f267615 100644
--- a/src/com/android/contacts/util/DataStatus.java
+++ b/src/com/android/contacts/util/DataStatus.java
@@ -94,6 +94,10 @@
return mStatus;
}
+ public long getTimestamp() {
+ return mTimestamp;
+ }
+
/**
* Build any timestamp and label into a single string.
*/
diff --git a/src/com/android/contacts/util/DateUtils.java b/src/com/android/contacts/util/DateUtils.java
index 40570f0..ed9eb94 100644
--- a/src/com/android/contacts/util/DateUtils.java
+++ b/src/com/android/contacts/util/DateUtils.java
@@ -22,40 +22,51 @@
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
/**
* Utility methods for processing dates.
*/
public class DateUtils {
- public static final SimpleDateFormat NO_YEAR_DATE_FORMAT = new SimpleDateFormat("--MM-dd");
- public static final SimpleDateFormat FULL_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
+ public static final TimeZone UTC_TIMEZONE = TimeZone.getTimeZone("UTC");
+
+ // 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'");
+ new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
// 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 = {
FULL_DATE_FORMAT,
DATE_AND_TIME_FORMAT,
- new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'"),
- new SimpleDateFormat("yyyyMMdd"),
- new SimpleDateFormat("yyyyMMdd'T'HHmmssSSS'Z'"),
- new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'"),
- new SimpleDateFormat("yyyyMMdd'T'HHmm'Z'"),
+ 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);
- }
- }
-
private static final java.text.DateFormat FORMAT_WITHOUT_YEAR_MONTH_FIRST =
new SimpleDateFormat("MMMM dd");
private static final java.text.DateFormat FORMAT_WITHOUT_YEAR_DATE_FIRST =
new SimpleDateFormat("dd MMMM");
+ static {
+ for (SimpleDateFormat format : DATE_FORMATS) {
+ format.setLenient(true);
+ format.setTimeZone(UTC_TIMEZONE);
+ }
+ NO_YEAR_DATE_FORMAT.setTimeZone(UTC_TIMEZONE);
+ FORMAT_WITHOUT_YEAR_MONTH_FIRST.setTimeZone(UTC_TIMEZONE);
+ FORMAT_WITHOUT_YEAR_DATE_FIRST.setTimeZone(UTC_TIMEZONE);
+ }
+
/**
* Parses the supplied string to see if it looks like a date. If so,
* returns the date. Otherwise, returns null.
@@ -77,7 +88,7 @@
/**
* Parses the supplied string to see if it looks like a date. If so,
- * returns the same date in a cleaned-up format. Otherwise, returns
+ * returns the same date in a cleaned-up format for the user. Otherwise, returns
* the supplied string unchanged.
*/
public static String formatDate(Context context, String string) {
@@ -114,9 +125,8 @@
date = f.parse(string, parsePosition);
if (parsePosition.getIndex() == string.length()) {
java.text.DateFormat outFormat = DateFormat.getDateFormat(context);
- synchronized (outFormat) {
- return outFormat.format(date);
- }
+ outFormat.setTimeZone(UTC_TIMEZONE);
+ return outFormat.format(date);
}
}
}
diff --git a/src/com/android/contacts/util/NameConverter.java b/src/com/android/contacts/util/NameConverter.java
new file mode 100644
index 0000000..9853821
--- /dev/null
+++ b/src/com/android/contacts/util/NameConverter.java
@@ -0,0 +1,166 @@
+/*
+ * 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.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 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);
+
+ 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);
+
+ 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);
+ }
+ }
+}
diff --git a/src/com/android/contacts/util/NotifyingAsyncQueryHandler.java b/src/com/android/contacts/util/NotifyingAsyncQueryHandler.java
index 83fae29..c8cfc8d 100644
--- a/src/com/android/contacts/util/NotifyingAsyncQueryHandler.java
+++ b/src/com/android/contacts/util/NotifyingAsyncQueryHandler.java
@@ -29,8 +29,6 @@
* <p>
* This pattern can be used to perform background queries without leaking
* {@link Context} objects.
- *
- * @hide pending API council review
*/
public class NotifyingAsyncQueryHandler extends AsyncQueryHandler {
private WeakReference<AsyncQueryListener> mListener;
diff --git a/src/com/android/contacts/util/PhoneCapabilityTester.java b/src/com/android/contacts/util/PhoneCapabilityTester.java
index 961e3c9..d3a8060 100644
--- a/src/com/android/contacts/util/PhoneCapabilityTester.java
+++ b/src/com/android/contacts/util/PhoneCapabilityTester.java
@@ -16,6 +16,8 @@
package com.android.contacts.util;
+import com.android.contacts.R;
+
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -58,7 +60,7 @@
private static void initialize(Context context) {
final TelephonyManager telephonyManager = new TelephonyManager(context);
sIsPhone = telephonyManager.isVoiceCapable();
- sIsSipPhone = SipManager.isVoipSupported(context);
+ sIsSipPhone = sIsPhone && SipManager.isVoipSupported(context);
sIsInitialized = true;
}
@@ -79,4 +81,12 @@
Uri.fromParts(Constants.SCHEME_SMSTO, "", null));
return isIntentRegistered(context, intent);
}
+
+ /**
+ * True if we are using two-pane layouts ("tablet mode"), false if we are using single views
+ * ("phone mode")
+ */
+ public static boolean isUsingTwoPanes(Context context) {
+ return context.getResources().getBoolean(R.bool.config_use_two_panes);
+ }
}
diff --git a/src/com/android/contacts/vcard/ExportProcessor.java b/src/com/android/contacts/vcard/ExportProcessor.java
index c5f293b..7b5e001 100644
--- a/src/com/android/contacts/vcard/ExportProcessor.java
+++ b/src/com/android/contacts/vcard/ExportProcessor.java
@@ -22,18 +22,22 @@
import android.app.Notification;
import android.app.NotificationManager;
-import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.RawContactsEntity;
import android.text.TextUtils;
import android.util.Log;
-import android.widget.RemoteViews;
+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).
@@ -92,6 +96,7 @@
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()) {
@@ -109,7 +114,7 @@
final String errorReason =
mService.getString(R.string.fail_reason_could_not_open_file,
uri, e.getMessage());
- doFinishNotification(errorReason, "");
+ doFinishNotification(errorReason, null);
return;
}
@@ -129,9 +134,14 @@
// VCardConfig.FLAG_USE_QP_TO_PRIMARY_PROPERTIES);
// composer = new VCardComposer(ExportVCardActivity.this, vcardType, true);
- composer.addHandler(composer.new HandlerForOutputStream(outputStream));
-
- if (!composer.init()) {
+ writer = new BufferedWriter(new OutputStreamWriter(outputStream));
+ final Uri contentUriForRawContactsEntity = RawContactsEntity.CONTENT_URI.buildUpon()
+ .appendQueryParameter(RawContactsEntity.FOR_EXPORT_ONLY, "1")
+ .build();
+ // 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 =
@@ -139,7 +149,7 @@
final String title =
mService.getString(R.string.fail_reason_could_not_initialize_exporter,
translatedErrorReason);
- doFinishNotification(title, "");
+ doFinishNotification(title, null);
return;
}
@@ -147,7 +157,7 @@
if (total == 0) {
final String title =
mService.getString(R.string.fail_reason_no_exportable_contact);
- doFinishNotification(title, "");
+ doFinishNotification(title, null);
return;
}
@@ -157,7 +167,9 @@
Log.i(LOG_TAG, "Export request is cancelled during composing vCard");
return;
}
- if (!composer.createOneEntry()) {
+ 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 =
@@ -165,7 +177,7 @@
final String title =
mService.getString(R.string.fail_reason_error_occurred_during_export,
translatedErrorReason);
- doFinishNotification(title, "");
+ doFinishNotification(title, null);
return;
}
@@ -178,16 +190,27 @@
}
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 = uri.getLastPathSegment();
final String title = mService.getString(R.string.exporting_vcard_finished_title,
filename);
- doFinishNotification(title, "");
+ 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);
}
}
diff --git a/src/com/android/contacts/vcard/ImportProcessor.java b/src/com/android/contacts/vcard/ImportProcessor.java
index 1b70025..4ea1ead 100644
--- a/src/com/android/contacts/vcard/ImportProcessor.java
+++ b/src/com/android/contacts/vcard/ImportProcessor.java
@@ -198,7 +198,7 @@
}
final Notification notification =
VCardService.constructFinishNotification(mService,
- description, description, intent);
+ description, null, intent);
mNotificationManager.notify(mJobId, notification);
}
diff --git a/src/com/android/contacts/vcard/ImportVCardActivity.java b/src/com/android/contacts/vcard/ImportVCardActivity.java
index b3376e9..17b89c3 100644
--- a/src/com/android/contacts/vcard/ImportVCardActivity.java
+++ b/src/com/android/contacts/vcard/ImportVCardActivity.java
@@ -21,7 +21,6 @@
import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.util.AccountSelectionUtil;
import com.android.vcard.VCardEntryCounter;
-import com.android.vcard.VCardInterpreterCollection;
import com.android.vcard.VCardParser;
import com.android.vcard.VCardParser_V21;
import com.android.vcard.VCardParser_V30;
@@ -399,7 +398,6 @@
final ContentResolver resolver = ImportVCardActivity.this.getContentResolver();
VCardEntryCounter counter = null;
VCardSourceDetector detector = null;
- VCardInterpreterCollection interpreter = null;
int vcardVersion = VCARD_VERSION_V21;
try {
boolean shouldUseV30 = false;
@@ -408,9 +406,9 @@
try {
counter = new VCardEntryCounter();
detector = new VCardSourceDetector();
- interpreter = new VCardInterpreterCollection(
- Arrays.asList(counter, detector));
- mVCardParser.parse(is, interpreter);
+ mVCardParser.addInterpreter(counter);
+ mVCardParser.addInterpreter(detector);
+ mVCardParser.parse(is);
} catch (VCardVersionException e1) {
try {
is.close();
@@ -423,9 +421,9 @@
try {
counter = new VCardEntryCounter();
detector = new VCardSourceDetector();
- interpreter = new VCardInterpreterCollection(
- Arrays.asList(counter, detector));
- mVCardParser.parse(is, interpreter);
+ mVCardParser.addInterpreter(counter);
+ mVCardParser.addInterpreter(detector);
+ mVCardParser.parse(is);
} catch (VCardVersionException e2) {
throw new VCardException("vCard with unspported version.");
}
diff --git a/src/com/android/contacts/vcard/ProcessorBase.java b/src/com/android/contacts/vcard/ProcessorBase.java
index 833090d..073bcbb 100644
--- a/src/com/android/contacts/vcard/ProcessorBase.java
+++ b/src/com/android/contacts/vcard/ProcessorBase.java
@@ -39,6 +39,7 @@
*/
public abstract int getType();
+ @Override
public abstract void run();
/**
@@ -49,8 +50,11 @@
*
* @see Future#cancel(boolean)
*/
+ @Override
public abstract boolean cancel(boolean mayInterruptIfRunning);
+ @Override
public abstract boolean isCancelled();
+ @Override
public abstract boolean isDone();
/**
diff --git a/src/com/android/contacts/vcard/VCardService.java b/src/com/android/contacts/vcard/VCardService.java
index 6422163..a4c0480 100644
--- a/src/com/android/contacts/vcard/VCardService.java
+++ b/src/com/android/contacts/vcard/VCardService.java
@@ -24,6 +24,8 @@
import android.content.Context;
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.Handler;
import android.os.IBinder;
@@ -36,8 +38,10 @@
import android.widget.Toast;
import java.io.File;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@@ -101,6 +105,33 @@
}
});
+ 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);
+ }
+ }
+
private NotificationManager mNotificationManager;
// Should be single thread, as we don't want to simultaneously handle import and export
@@ -113,6 +144,11 @@
// Key is jobId.
private final Map<Integer, ProcessorBase> mRunningJobMap =
new HashMap<Integer, 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>();
/* ** vCard exporter params ** */
// If true, VCardExporter is able to emits files longer than 8.3 format.
@@ -286,7 +322,7 @@
} else {
Log.w(LOG_TAG, String.format("Tried to remove unknown job (id: %d)", jobId));
}
- stopServiceWhenNoJob();
+ stopServiceIfAppropriate();
}
private synchronized void handleRequestAvailableExportDestination(Message msg) {
@@ -310,10 +346,11 @@
}
/**
- * Checks job list and call {@link #stopSelf()} when there's no job now.
- * A new job cannot be submitted any more after this call.
+ * 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 stopServiceWhenNoJob() {
+ private synchronized void stopServiceIfAppropriate() {
if (mRunningJobMap.size() > 0) {
for (final Map.Entry<Integer, ProcessorBase> entry : mRunningJobMap.entrySet()) {
final int jobId = entry.getKey();
@@ -327,11 +364,41 @@
}
}
+ 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) {
@@ -341,7 +408,7 @@
if (mRunningJobMap.remove(jobId) == null) {
Log.w(LOG_TAG, String.format("Tried to remove unknown job (id: %d)", jobId));
}
- stopServiceWhenNoJob();
+ stopServiceIfAppropriate();
}
/* package */ synchronized void handleFinishExportNotification(
@@ -362,7 +429,7 @@
mReservedDestination.remove(path);
}
- stopServiceWhenNoJob();
+ stopServiceIfAppropriate();
}
/**
diff --git a/src/com/android/contacts/widget/TextHighlightingAnimation.java b/src/com/android/contacts/widget/TextHighlightingAnimation.java
index 21bbc63..882dd48 100644
--- a/src/com/android/contacts/widget/TextHighlightingAnimation.java
+++ b/src/com/android/contacts/widget/TextHighlightingAnimation.java
@@ -15,6 +15,7 @@
*/
package com.android.contacts.widget;
+import com.android.contacts.format.FormatUtils;
import com.android.internal.R;
import android.database.CharArrayBuffer;
@@ -72,7 +73,7 @@
// TODO figure out a way to avoid string allocation
mString = new String(mText.data, 0, mText.sizeCopied);
- int index = indexOf(baseText, highlightedText);
+ int index = FormatUtils.overlapPoint(baseText, highlightedText);
if (index == 0 || index == -1) {
mDimmingEnabled = false;
@@ -83,42 +84,6 @@
}
}
- /**
- * An implementation of indexOf on CharArrayBuffers that finds the first match of
- * the start of buffer2 in buffer1. For example, indexOf("abcd", "cdef") == 2
- */
- private int indexOf(CharArrayBuffer buffer1, CharArrayBuffer buffer2) {
- char[] string1 = buffer1.data;
- char[] string2 = buffer2.data;
- int count1 = buffer1.sizeCopied;
- int count2 = buffer2.sizeCopied;
-
- // Ignore matching tails of the two buffers
- while (count1 > 0 && count2 > 0 && string1[count1 - 1] == string2[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 (string1[i+j] != string2[j]) {
- break;
- }
- }
- if (j == size) {
- return i;
- }
- }
-
- return -1;
- }
-
-
@SuppressWarnings("unchecked")
public <T> T[] getSpans(int start, int end, Class<T> type) {
if (mDimmingEnabled) {
diff --git a/tests/res/values/donottranslate_strings.xml b/tests/res/values/donottranslate_strings.xml
index 8557fd6..bd272c3 100644
--- a/tests/res/values/donottranslate_strings.xml
+++ b/tests/res/values/donottranslate_strings.xml
@@ -32,6 +32,7 @@
<item>ACTION_PICK: phone (legacy)</item>
<item>ACTION_PICK: postal</item>
<item>ACTION_PICK: postal (legacy)</item>
+ <item>ACTION_PICK: e-mail</item>
<item>ACTION_CREATE_SHORTCUT: contact</item>
<item>ACTION_CREATE_SHORTCUT: dial</item>
<item>ACTION_CREATE_SHORTCUT: message</item>
diff --git a/tests/src/com/android/contacts/ContactLoaderTest.java b/tests/src/com/android/contacts/ContactLoaderTest.java
index 503fc64..0e0e2b0 100644
--- a/tests/src/com/android/contacts/ContactLoaderTest.java
+++ b/tests/src/com/android/contacts/ContactLoaderTest.java
@@ -29,10 +29,12 @@
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.StatusUpdates;
import android.test.LoaderTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
/**
* Runs ContactLoader tests for the the contact-detail and editor view.
*/
+@LargeTest
public class ContactLoaderTest extends LoaderTestCase {
ContactsMockContext mMockContext;
MockContentProvider mContactsProvider;
@@ -265,7 +267,8 @@
mContactsProvider.expectQuery(baseUri)
.withProjection(new String[] {
Contacts.NAME_RAW_CONTACT_ID, Contacts.DISPLAY_NAME_SOURCE,
- Contacts.LOOKUP_KEY, Contacts.DISPLAY_NAME, Contacts.PHONETIC_NAME,
+ 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,
@@ -299,7 +302,7 @@
.withSortOrder(Contacts.Entity.RAW_CONTACT_ID)
.returnRow(
rawContactId, 40,
- "aa%12%@!", "John Doe", "jdo",
+ "aa%12%@!", "John Doe", "Doe, John", "jdo",
0, 0, StatusUpdates.AVAILABLE,
"Having lunch", 0,
"mockPkg1", 10,
diff --git a/tests/src/com/android/contacts/DialerLaunchPerformance.java b/tests/src/com/android/contacts/DialerLaunchPerformance.java
index ae78082..0803c6b 100644
--- a/tests/src/com/android/contacts/DialerLaunchPerformance.java
+++ b/tests/src/com/android/contacts/DialerLaunchPerformance.java
@@ -32,7 +32,7 @@
mIntent.setAction(Intent.ACTION_MAIN);
mIntent.addCategory(Intent.CATEGORY_LAUNCHER);
mIntent.setComponent(new ComponentName("com.android.contacts",
- "com.android.contacts.DialtactsActivity"));
+ "com.android.contacts.activities.DialtactsActivity"));
start();
}
diff --git a/tests/src/com/android/contacts/EntityModifierTests.java b/tests/src/com/android/contacts/EntityModifierTests.java
index 4acaa92..63dd84d 100644
--- a/tests/src/com/android/contacts/EntityModifierTests.java
+++ b/tests/src/com/android/contacts/EntityModifierTests.java
@@ -20,23 +20,31 @@
import static android.content.ContentProviderOperation.TYPE_INSERT;
import static android.content.ContentProviderOperation.TYPE_UPDATE;
+import com.google.android.collect.Lists;
+
import com.android.contacts.model.AccountType;
-import com.android.contacts.model.AccountType.DataKind;
import com.android.contacts.model.AccountType.EditType;
import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.DataKind;
import com.android.contacts.model.EntityDelta;
import com.android.contacts.model.EntityDelta.ValuesDelta;
import com.android.contacts.model.EntityDeltaList;
import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.ExchangeAccountType;
+import com.android.contacts.model.GoogleAccountType;
+import com.android.contacts.tests.mocks.ContactsMockContext;
import com.android.contacts.tests.mocks.MockAccountTypeManager;
-import com.google.android.collect.Lists;
+import com.android.contacts.tests.mocks.MockContentProvider;
import android.content.ContentProviderOperation;
import android.content.ContentValues;
import android.content.Context;
import android.content.Entity;
+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;
@@ -81,45 +89,54 @@
MockContactsSource() {
this.accountType = TEST_ACCOUNT_TYPE;
+ final DataKind nameKind = new DataKind(StructuredName.CONTENT_ITEM_TYPE,
+ R.string.nameLabelsGroup, -1, -1, true, -1, -1, -1);
+ nameKind.typeOverallMax = 1;
+ addKind(nameKind);
+
// Phone allows maximum 2 home, 1 work, and unlimited other, with
// constraint of 5 numbers maximum.
- DataKind kind = new DataKind(Phone.CONTENT_ITEM_TYPE, -1, -1, 10, true);
+ final DataKind phoneKind = new DataKind(
+ Phone.CONTENT_ITEM_TYPE, -1, -1, 10, true, -1, -1, -1);
- kind.typeOverallMax = 5;
- kind.typeColumn = Phone.TYPE;
- kind.typeList = Lists.newArrayList();
- kind.typeList.add(new EditType(Phone.TYPE_HOME, -1).setSpecificMax(2));
- kind.typeList.add(new EditType(Phone.TYPE_WORK, -1).setSpecificMax(1));
- kind.typeList.add(new EditType(Phone.TYPE_FAX_WORK, -1).setSecondary(true));
- kind.typeList.add(new EditType(Phone.TYPE_OTHER, -1));
+ 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));
- kind.fieldList = Lists.newArrayList();
- kind.fieldList.add(new EditField(Phone.NUMBER, -1, -1));
- kind.fieldList.add(new EditField(Phone.LABEL, -1, -1));
+ phoneKind.fieldList = Lists.newArrayList();
+ phoneKind.fieldList.add(new EditField(Phone.NUMBER, -1, -1));
+ phoneKind.fieldList.add(new EditField(Phone.LABEL, -1, -1));
- addKind(kind);
+ addKind(phoneKind);
// Email is unlimited
- kind = new DataKind(Email.CONTENT_ITEM_TYPE, -1, -1, 10, true);
- kind.typeOverallMax = -1;
- kind.fieldList = Lists.newArrayList();
- kind.fieldList.add(new EditField(Email.DATA, -1, -1));
- addKind(kind);
+ final DataKind emailKind = new DataKind(
+ Email.CONTENT_ITEM_TYPE, -1, -1, 10, true, -1, -1, -1);
+ emailKind.typeOverallMax = -1;
+ emailKind.fieldList = Lists.newArrayList();
+ emailKind.fieldList.add(new EditField(Email.DATA, -1, -1));
+ addKind(emailKind);
// IM is only one
- kind = new DataKind(Im.CONTENT_ITEM_TYPE, -1, -1, 10, true);
- kind.typeOverallMax = 1;
- kind.fieldList = Lists.newArrayList();
- kind.fieldList.add(new EditField(Im.DATA, -1, -1));
- addKind(kind);
+ final DataKind imKind = new DataKind(Im.CONTENT_ITEM_TYPE, -1, -1, 10,
+ true, -1, -1, -1);
+ imKind.typeOverallMax = 1;
+ imKind.fieldList = Lists.newArrayList();
+ imKind.fieldList.add(new EditField(Im.DATA, -1, -1));
+ addKind(imKind);
// Organization is only one
- kind = new DataKind(Organization.CONTENT_ITEM_TYPE, -1, -1, 10, true);
- kind.typeOverallMax = 1;
- kind.fieldList = Lists.newArrayList();
- kind.fieldList.add(new EditField(Organization.COMPANY, -1, -1));
- kind.fieldList.add(new EditField(Organization.TITLE, -1, -1));
- addKind(kind);
+ final DataKind orgKind = new DataKind(
+ Organization.CONTENT_ITEM_TYPE, -1, -1, 10, true, -1, -1, -1);
+ 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);
}
@Override
@@ -330,7 +347,7 @@
// Test row that has type values, but core fields are empty
final EntityDelta state = getEntity(TEST_ID);
- final ValuesDelta values = EntityModifier.insertChild(state, kindPhone, typeHome);
+ EntityModifier.insertChild(state, kindPhone, typeHome);
// Build diff, expecting insert for data row and update enforcement
final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
@@ -420,7 +437,7 @@
public void testTrimEmptyUntouched() {
final AccountType source = getAccountType();
final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+ EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
// Build "before" that has empty row
final EntityDelta state = getEntity(TEST_ID);
@@ -497,7 +514,7 @@
final AccountType accountType = getAccountType();
final AccountTypeManager accountTypes = getAccountTypes(accountType);
final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+ EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
// Try creating a contact without any child entries
final EntityDelta state = getEntity(null);
@@ -528,7 +545,7 @@
// Try creating a contact with single empty entry
final EntityDelta state = getEntity(null);
- final ValuesDelta values = EntityModifier.insertChild(state, kindPhone, typeHome);
+ EntityModifier.insertChild(state, kindPhone, typeHome);
final EntityDeltaList set = EntityDeltaList.fromSingle(state);
// Build diff, expecting two insert operations
@@ -746,4 +763,448 @@
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(), "");
+ DataKind kind = newAccountType.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE);
+
+ ContactsMockContext context = new ContactsMockContext(getContext());
+
+ EntityDelta oldState = new EntityDelta();
+ 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));
+
+ EntityDelta newState = new EntityDelta();
+ EntityModifier.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(), "");
+ 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);
+
+ EntityDelta oldState = new EntityDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+ mockNameValues.put(StructuredName.DISPLAY_NAME, inputDisplayName);
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ EntityDelta newState = new EntityDelta();
+ EntityModifier.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(), "");
+ 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);
+
+ EntityDelta oldState = new EntityDelta();
+ 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));
+
+ EntityDelta newState = new EntityDelta();
+ EntityModifier.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(), "");
+ DataKind kind = newAccountType.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE);
+
+ EntityDelta oldState = new EntityDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
+ mockNameValues.put(StructuredPostal.FORMATTED_ADDRESS, "formatted_address");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ EntityDelta newState = new EntityDelta();
+ EntityModifier.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(), "");
+ AccountType newAccountType = new GoogleAccountType(getContext(), "");
+ DataKind kind = newAccountType.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE);
+
+ EntityDelta oldState = new EntityDelta();
+ 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));
+
+ EntityDelta newState = new EntityDelta();
+ EntityModifier.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(), ""));
+ }
+
+ public void testMigrateEventFromExchangeToGoogle() {
+ testMigrateEventCommon(new ExchangeAccountType(getContext(), ""),
+ new GoogleAccountType(getContext(), ""));
+ }
+
+ private void testMigrateEventCommon(AccountType oldAccountType, AccountType newAccountType) {
+ DataKind kind = newAccountType.getKindForMimetype(Event.CONTENT_ITEM_TYPE);
+
+ EntityDelta oldState = new EntityDelta();
+ 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));
+
+ EntityDelta newState = new EntityDelta();
+ EntityModifier.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(), "");
+ DataKind kind = newAccountType.getKindForMimetype(Event.CONTENT_ITEM_TYPE);
+
+ EntityDelta oldState = new EntityDelta();
+ 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));
+
+ EntityDelta newState = new EntityDelta();
+ EntityModifier.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(), "");
+ DataKind kind = newAccountType.getKindForMimetype(Email.CONTENT_ITEM_TYPE);
+
+ EntityDelta oldState = new EntityDelta();
+ 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));
+
+ EntityDelta newState = new EntityDelta();
+ EntityModifier.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(), "");
+ DataKind kind = newAccountType.getKindForMimetype(Im.CONTENT_ITEM_TYPE);
+
+ EntityDelta oldState = new EntityDelta();
+ 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));
+
+ EntityDelta newState = new EntityDelta();
+ EntityModifier.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(), "");
+ DataKind kind = newAccountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+
+ EntityDelta oldState = new EntityDelta();
+ 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_MOBILE);
+ 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 HOME
+ 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();
+
+ // This field should be ignored, as Exchange only allows 2 HOME phone numbers while we
+ // already have that number of HOME phones.
+ 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));
+
+ EntityDelta newState = new EntityDelta();
+ EntityModifier.migrateGenericWithTypeColumn(oldState, newState, kind);
+
+ List<ValuesDelta> list = newState.getMimeEntries(Phone.CONTENT_ITEM_TYPE);
+ assertNotNull(list);
+ assertEquals(4, list.size());
+
+ int defaultType = kind.typeList.get(0).rawValue;
+
+ 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_MOBILE, 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(), "");
+ DataKind kind = newAccountType.getKindForMimetype(Organization.CONTENT_ITEM_TYPE);
+
+ EntityDelta oldState = new EntityDelta();
+ 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));
+
+ EntityDelta newState = new EntityDelta();
+ EntityModifier.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/RecentCallsListActivityTests.java b/tests/src/com/android/contacts/activities/CallLogActivityTests.java
similarity index 92%
rename from tests/src/com/android/contacts/RecentCallsListActivityTests.java
rename to tests/src/com/android/contacts/activities/CallLogActivityTests.java
index 3c2a9fe..ef1afd0 100644
--- a/tests/src/com/android/contacts/RecentCallsListActivityTests.java
+++ b/tests/src/com/android/contacts/activities/CallLogActivityTests.java
@@ -14,23 +14,22 @@
* limitations under the License.
*/
-package com.android.contacts;
+package com.android.contacts.activities;
+
+import com.android.contacts.calllog.CallLogFragment;
+import com.android.internal.telephony.CallerInfo;
import android.content.res.Resources;
-import android.database.Cursor;
import android.database.MatrixCursor;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
import android.provider.CallLog.Calls;
import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.MediumTest;
-import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;
-import com.android.contacts.RecentCallsListActivity;
-import com.android.internal.telephony.CallerInfo;
+
import java.util.Date;
import java.util.Formatter;
import java.util.HashMap;
@@ -46,10 +45,10 @@
* adb shell am instrument \
* -w com.android.contacts.tests/android.test.InstrumentationTestRunner
*/
-
-public class RecentCallsListActivityTests
- extends ActivityInstrumentationTestCase2<RecentCallsListActivity> {
- static private final String TAG = "RecentCallsListActivityTests";
+@LargeTest
+public class CallLogActivityTests
+ extends ActivityInstrumentationTestCase2<CallLogActivity> {
+ static private final String TAG = "CallLogActivityTests";
static private final String[] CALL_LOG_PROJECTION = new String[] {
Calls._ID,
Calls.NUMBER,
@@ -66,11 +65,12 @@
// We get the call list activity and assign is a frame to build
// its list. mAdapter is an inner class of
- // RecentCallsListActivity to build the rows (view) in the call
+ // CallLogActivity to build the rows (view) in the call
// list. We reuse it with our own in-mem DB.
- private RecentCallsListActivity mActivity;
+ private CallLogActivity mActivity;
+ private CallLogFragment mFragment;
private FrameLayout mParentView;
- private RecentCallsListActivity.RecentCallsAdapter mAdapter;
+ private CallLogFragment.CallLogAdapter mAdapter;
private String mVoicemail;
// In memory array to hold the rows corresponding to the 'calls' table.
@@ -85,13 +85,13 @@
private HashMap<Integer, Bitmap> mCallTypeIcons;
// An item in the call list. All the methods performing checks use it.
- private RecentCallsListActivity.RecentCallsListItemViews mItem;
+ private CallLogFragment.CallLogListItemViews mItem;
// The list of views representing the data in the DB. View are in
// reverse order compare to the DB.
private View[] mList;
- public RecentCallsListActivityTests() {
- super("com.android.contacts", RecentCallsListActivity.class);
+ public CallLogActivityTests() {
+ super("com.android.contacts", CallLogActivity.class);
mIndex = 1;
mRnd = new Random();
}
@@ -99,8 +99,9 @@
@Override
public void setUp() {
mActivity = getActivity();
- mVoicemail = mActivity.mVoiceMailNumber;
- mAdapter = mActivity.mAdapter;
+ mFragment = mActivity.getFragment();
+ mVoicemail = mFragment.getVoiceMailNumber();
+ mAdapter = mFragment.getAdapter();
mParentView = new FrameLayout(mActivity);
mCursor = new MatrixCursor(CALL_LOG_PROJECTION);
buildIconMap();
@@ -170,7 +171,7 @@
if (null == mList[i]) {
break;
}
- mItem = (RecentCallsListActivity.RecentCallsListItemViews) mList[i].getTag();
+ mItem = (CallLogFragment.CallLogListItemViews) mList[i].getTag();
// callView tag is the phone number.
String number = (String) mItem.callView.getTag();
diff --git a/tests/src/com/android/contacts/activities/ContactBrowserActivityTest.java b/tests/src/com/android/contacts/activities/ContactBrowserActivityTest.java
index 912950f..d165963 100644
--- a/tests/src/com/android/contacts/activities/ContactBrowserActivityTest.java
+++ b/tests/src/com/android/contacts/activities/ContactBrowserActivityTest.java
@@ -16,6 +16,7 @@
package com.android.contacts.activities;
+import com.android.contacts.ContactPhotoManager;
import com.android.contacts.ContactsApplication;
import com.android.contacts.R;
import com.android.contacts.detail.ContactDetailFragment;
@@ -26,9 +27,11 @@
import com.android.contacts.test.InjectedServices;
import com.android.contacts.tests.mocks.ContactsMockContext;
import com.android.contacts.tests.mocks.MockAccountTypeManager;
+import com.android.contacts.tests.mocks.MockContactPhotoManager;
import com.android.contacts.tests.mocks.MockContentProvider;
import com.android.contacts.tests.mocks.MockContentProvider.Query;
import com.android.contacts.tests.mocks.MockSharedPreferences;
+import com.android.contacts.util.PhoneCapabilityTester;
import android.accounts.Account;
import android.content.ContentValues;
@@ -85,7 +88,8 @@
InjectedServices services = new InjectedServices();
services.setContentResolver(mContext.getContentResolver());
services.setSharedPreferences(new MockSharedPreferences());
-
+ services.setSystemService(ContactPhotoManager.CONTACT_PHOTO_SERVICE,
+ new MockContactPhotoManager());
AccountType accountType = new BaseAccountType();
accountType.accountType = TEST_ACCOUNT_TYPE;
@@ -98,6 +102,10 @@
}
public void testSingleAccountNoGroups() {
+ // This two-pane UI test only makes sense if we run with two panes.
+ // Let's ignore this in the single pane case
+ if (!PhoneCapabilityTester.isUsingTwoPanes(mContext)) return;
+
expectSettingsQueriesAndReturnDefault();
expectProviderStatusQueryAndReturnNormal();
expectGroupsQueryAndReturnEmpty();
diff --git a/tests/src/com/android/contacts/detail/ContactDetailFragmentTests.java b/tests/src/com/android/contacts/detail/ContactDetailFragmentTests.java
index 4cee32c..cfab94a 100644
--- a/tests/src/com/android/contacts/detail/ContactDetailFragmentTests.java
+++ b/tests/src/com/android/contacts/detail/ContactDetailFragmentTests.java
@@ -16,7 +16,7 @@
package com.android.contacts.detail;
-import com.android.contacts.detail.ContactDetailFragment.ViewEntry;
+import com.android.contacts.detail.ContactDetailFragment.DetailViewEntry;
import android.content.ContentValues;
import android.content.Intent;
@@ -42,7 +42,7 @@
values.put(Im.PROTOCOL, Im.PROTOCOL_GOOGLE_TALK);
values.put(Im.DATA, TEST_ADDRESS);
- ViewEntry entry = new ContactDetailFragment.ViewEntry();
+ DetailViewEntry entry = new ContactDetailFragment.DetailViewEntry();
ContactDetailFragment.buildImActions(entry, values);
assertEquals(Intent.ACTION_SENDTO, entry.intent.getAction());
assertEquals("xmpp:" + TEST_ADDRESS + "?message", entry.intent.getData().toString());
@@ -59,7 +59,7 @@
values.put(Im.DATA, TEST_ADDRESS);
values.put(Im.CHAT_CAPABILITY, Im.CAPABILITY_HAS_VOICE | Im.CAPABILITY_HAS_VIDEO);
- ViewEntry entry = new ContactDetailFragment.ViewEntry();
+ DetailViewEntry entry = new ContactDetailFragment.DetailViewEntry();
ContactDetailFragment.buildImActions(entry, values);
assertEquals(Intent.ACTION_SENDTO, entry.intent.getAction());
assertEquals("xmpp:" + TEST_ADDRESS + "?message", entry.intent.getData().toString());
@@ -78,7 +78,7 @@
values.put(Im.CHAT_CAPABILITY, Im.CAPABILITY_HAS_VOICE | Im.CAPABILITY_HAS_VIDEO |
Im.CAPABILITY_HAS_VOICE);
- ViewEntry entry = new ContactDetailFragment.ViewEntry();
+ DetailViewEntry entry = new ContactDetailFragment.DetailViewEntry();
ContactDetailFragment.buildImActions(entry, values);
assertEquals(Intent.ACTION_SENDTO, entry.intent.getAction());
assertEquals("xmpp:" + TEST_ADDRESS + "?message", entry.intent.getData().toString());
@@ -97,7 +97,7 @@
values.put(Im.CUSTOM_PROTOCOL, TEST_PROTOCOL);
values.put(Im.DATA, TEST_ADDRESS);
- ViewEntry entry = new ContactDetailFragment.ViewEntry();
+ DetailViewEntry entry = new ContactDetailFragment.DetailViewEntry();
ContactDetailFragment.buildImActions(entry, values);
assertEquals(Intent.ACTION_SENDTO, entry.intent.getAction());
@@ -120,7 +120,7 @@
values.put(Email.CHAT_CAPABILITY, Im.CAPABILITY_HAS_VOICE | Im.CAPABILITY_HAS_VIDEO |
Im.CAPABILITY_HAS_VOICE);
- ViewEntry entry = new ContactDetailFragment.ViewEntry();
+ DetailViewEntry entry = new ContactDetailFragment.DetailViewEntry();
ContactDetailFragment.buildImActions(entry, values);
assertEquals(Intent.ACTION_SENDTO, entry.intent.getAction());
assertEquals("xmpp:" + TEST_ADDRESS + "?message", entry.intent.getData().toString());
diff --git a/tests/src/com/android/contacts/format/FormatUtilsTests.java b/tests/src/com/android/contacts/format/FormatUtilsTests.java
new file mode 100644
index 0000000..0464adb
--- /dev/null
+++ b/tests/src/com/android/contacts/format/FormatUtilsTests.java
@@ -0,0 +1,35 @@
+/*
+ * 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.format;
+
+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"));
+ }
+}
diff --git a/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java b/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
index 4514e1e..1db0f4c 100644
--- a/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
+++ b/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
@@ -132,7 +132,7 @@
getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
- mFragment = ContactDeletionInteraction.start(activity, CONTACT_URI);
+ mFragment = ContactDeletionInteraction.start(activity, CONTACT_URI, false);
}
});
diff --git a/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java b/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java
index 43e844e..c401a8c 100644
--- a/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java
+++ b/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java
@@ -124,6 +124,26 @@
assertEquals("sms:456", interaction.startedIntent.getDataString());
}
+ public void testShouldCollapseWith() {
+ PhoneNumberInteraction.PhoneItem phoneItem1 = new PhoneNumberInteraction.PhoneItem();
+ PhoneNumberInteraction.PhoneItem phoneItem2 = new PhoneNumberInteraction.PhoneItem();
+
+ phoneItem1.phoneNumber = "123";
+ phoneItem2.phoneNumber = "123";
+
+ assertTrue(phoneItem1.shouldCollapseWith(phoneItem2));
+
+ phoneItem1.phoneNumber = "123";
+ phoneItem2.phoneNumber = "456";
+
+ assertFalse(phoneItem1.shouldCollapseWith(phoneItem2));
+
+ phoneItem1.phoneNumber = "123#,123";
+ phoneItem2.phoneNumber = "123#,456";
+
+ assertFalse(phoneItem1.shouldCollapseWith(phoneItem2));
+ }
+
public void testCallNumberWhenThereAreDuplicates() {
Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 13);
expectQuery(contactUri)
diff --git a/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java b/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
index 50a1f1f..03b6302 100644
--- a/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
+++ b/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
@@ -73,6 +73,7 @@
ACTION_PICK_PHONE_LEGACY,
ACTION_PICK_POSTAL,
ACTION_PICK_POSTAL_LEGACY,
+ ACTION_PICK_EMAIL,
ACTION_CREATE_SHORTCUT_CONTACT,
ACTION_CREATE_SHORTCUT_DIAL,
ACTION_CREATE_SHORTCUT_MESSAGE,
@@ -195,6 +196,11 @@
startContactSelectionActivityForResult(intent);
break;
}
+ case ACTION_PICK_EMAIL: {
+ startContactSelectionActivityForResult(
+ new Intent(Intent.ACTION_PICK, Email.CONTENT_URI));
+ break;
+ }
case ACTION_CREATE_SHORTCUT_CONTACT: {
Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
startContactSelectionActivityForResult(intent);
diff --git a/tests/src/com/android/contacts/tests/mocks/MockContactPhotoManager.java b/tests/src/com/android/contacts/tests/mocks/MockContactPhotoManager.java
new file mode 100644
index 0000000..6da205b
--- /dev/null
+++ b/tests/src/com/android/contacts/tests/mocks/MockContactPhotoManager.java
@@ -0,0 +1,54 @@
+/*
+ * 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.tests.mocks;
+
+import com.android.contacts.ContactPhotoManager;
+
+import android.net.Uri;
+import android.widget.ImageView;
+
+/**
+ * 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 loadPhoto(ImageView view, long photoId) {
+ view.setImageResource(mDefaultResourceId);
+ }
+
+ @Override
+ public void loadPhoto(ImageView view, Uri photoUri) {
+ view.setImageResource(mDefaultResourceId);
+ }
+
+ @Override
+ public void pause() {
+ }
+
+ @Override
+ public void resume() {
+ }
+
+ @Override
+ public void refreshCache() {
+ }
+
+ @Override
+ public void preloadPhotosInBackground() {
+ }
+}
diff --git a/tests/src/com/android/contacts/util/NameConverterTests.java b/tests/src/com/android/contacts/util/NameConverterTests.java
new file mode 100644
index 0000000..e1773a7
--- /dev/null
+++ b/tests/src/com/android/contacts/util/NameConverterTests.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.util;
+
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
+
+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);
+ }
+}