Merge change Ic0c20625 into eclair
* changes:
Don't hightlight call button in lists.
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 97dad56..b6a2045 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -62,7 +62,7 @@
<!-- Tab container for TwelveKeyDialer and RecentCallsList -->
<activity android:name="DialtactsActivity"
android:label="@string/launcherDialer"
- android:theme="@android:style/Theme.NoTitleBar"
+ android:theme="@style/DialtactsTheme"
android:launchMode="singleTask"
android:clearTaskOnLaunch="true"
android:icon="@drawable/ic_launcher_phone"
@@ -195,11 +195,6 @@
</intent-filter>
<intent-filter>
- <action android:name="com.android.contacts.action.JOIN_AGGREGATE" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
-
- <intent-filter>
<action android:name="android.intent.action.INSERT_OR_EDIT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/person" />
@@ -239,6 +234,18 @@
/>
</activity>
+ <!-- An activity for joining contacts -->
+ <activity android:name="ContactsListActivity$JoinContactActivity"
+ android:theme="@style/TallTitleBarTheme"
+ android:clearTaskOnLaunch="true"
+ >
+ <intent-filter>
+ <action android:name="com.android.contacts.action.JOIN_AGGREGATE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+
<!-- Used to select display and sync groups -->
<activity android:name=".ui.DisplayGroupsActivity" android:label="@string/displayGroups" />
@@ -419,5 +426,7 @@
<activity android:name=".ImportVCardActivity"
android:theme="@style/BackgroundOnly" />
+ <activity android:name=".ExportVCardActivity"
+ android:theme="@style/BackgroundOnly" />
</application>
</manifest>
diff --git a/res/drawable-hdpi-finger/ic_join.png b/res/drawable-hdpi-finger/ic_join.png
new file mode 100644
index 0000000..8f140d4
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_join.png
Binary files differ
diff --git a/res/drawable-hdpi/bg_infobar_new.9.png b/res/drawable-hdpi/bg_infobar_new.9.png
new file mode 100644
index 0000000..104ced9
--- /dev/null
+++ b/res/drawable-hdpi/bg_infobar_new.9.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_contacts.png b/res/drawable-hdpi/ic_launcher_contacts.png
new file mode 100644
index 0000000..73f5451
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_contacts.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_folder_live_contacts_phone.png b/res/drawable-hdpi/ic_launcher_folder_live_contacts_phone.png
new file mode 100644
index 0000000..70ce098
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_folder_live_contacts_phone.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_folder_live_contacts_starred.png b/res/drawable-hdpi/ic_launcher_folder_live_contacts_starred.png
new file mode 100644
index 0000000..a0c01ce
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_folder_live_contacts_starred.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_phone.png b/res/drawable-hdpi/ic_launcher_phone.png
new file mode 100644
index 0000000..47186c3
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_phone.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_join.png b/res/drawable-mdpi-finger/ic_join.png
new file mode 100644
index 0000000..177a582
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_join.png
Binary files differ
diff --git a/res/drawable-mdpi/bg_infobar_new.9.png b/res/drawable-mdpi/bg_infobar_new.9.png
new file mode 100644
index 0000000..f3a83d4
--- /dev/null
+++ b/res/drawable-mdpi/bg_infobar_new.9.png
Binary files differ
diff --git a/res/drawable/section_dark.9.png b/res/drawable/section_dark.9.png
new file mode 100644
index 0000000..5d1e1ae
--- /dev/null
+++ b/res/drawable/section_dark.9.png
Binary files differ
diff --git a/res/layout-finger/contact_card_layout.xml b/res/layout-finger/contact_card_layout.xml
index acfd8cb..3f090f5 100644
--- a/res/layout-finger/contact_card_layout.xml
+++ b/res/layout-finger/contact_card_layout.xml
@@ -29,13 +29,8 @@
android:id="@+id/below_header"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <!-- <View
- android:id="@+id/buffer_view"
- android:layout_height="wrap_content"
- android:layout_width="fill_parent"
- /> -->
+ android:orientation="vertical"
+ android:layout_weight="1">
<com.android.contacts.ScrollingTabWidget android:id="@+id/tab_widget"
android:layout_width="fill_parent"
diff --git a/res/layout-finger/contacts_list_content_join.xml b/res/layout-finger/contacts_list_content_join.xml
new file mode 100644
index 0000000..95f9c20
--- /dev/null
+++ b/res/layout-finger/contacts_list_content_join.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:background="@*android:drawable/title_bar_medium"
+ android:paddingLeft="5dip"
+ android:paddingRight="5dip"
+ android:gravity="center_vertical"
+ >
+
+ <ImageView
+ android:layout_width="48dip"
+ android:layout_height="48dip"
+ android:src="@drawable/ic_join"
+ android:gravity="center"
+ android:scaleType="fitCenter"
+ />
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingLeft="10dip">
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/titleJoinContactDataWith"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ />
+ <TextView
+ android:id="@+id/join_contact_blurb"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-2dip"
+ android:maxLines="2"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ />
+ </LinearLayout>
+ </LinearLayout>
+
+ <ListView android:id="@android:id/list"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:fastScrollEnabled="true"
+ />
+</LinearLayout>
+
diff --git a/res/layout-finger/dialpad.xml b/res/layout-finger/dialpad.xml
index 0acb721..82179db 100644
--- a/res/layout-finger/dialpad.xml
+++ b/res/layout-finger/dialpad.xml
@@ -21,8 +21,11 @@
android:id="@+id/dialpad"
android:paddingLeft="7dp"
android:paddingRight="7dp"
- android:layout_width="fill_parent"
+ android:paddingTop="6dp"
+ android:paddingBottom="6dp"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
>
<ImageButton android:id="@+id/one"
android:layout_width="88dp"
diff --git a/res/layout-finger/tab_account_name.xml b/res/layout-finger/tab_account_name.xml
new file mode 100644
index 0000000..dc99af1
--- /dev/null
+++ b/res/layout-finger/tab_account_name.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- looks like Widget.TextView.ListSeparator -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/account_name"
+ android:background="@drawable/bg_infobar_new"
+ android:layout_width="fill_parent"
+ android:layout_height="@dimen/account_name_height"
+ android:layout_below="@+id/tab_scroll_view"
+ android:textStyle="normal"
+ android:textColor="@*android:color/dim_foreground_dark"
+ android:textSize="12sp"
+ android:gravity="left|center_vertical"
+ android:paddingLeft="7dip"
+/>
diff --git a/res/layout-finger/tab_layout.xml b/res/layout-finger/tab_layout.xml
index 23359b7..9a793c3 100644
--- a/res/layout-finger/tab_layout.xml
+++ b/res/layout-finger/tab_layout.xml
@@ -15,6 +15,7 @@
-->
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/tab_scroll_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
diff --git a/res/layout-finger/total_contacts.xml b/res/layout-finger/total_contacts.xml
new file mode 100644
index 0000000..ab15ce1
--- /dev/null
+++ b/res/layout-finger/total_contacts.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/totalContactsText"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ style="?android:attr/listSeparatorTextViewStyle"
+ android:textColor="@*android:color/dim_foreground_dark"
+ android:textSize="12sp"
+ android:textStyle="normal"
+ android:background="@drawable/section_dark"
+ android:paddingLeft="7dp"
+ android:gravity="center|center_vertical"
+/>
\ No newline at end of file
diff --git a/res/layout-finger/twelve_key_dialer.xml b/res/layout-finger/twelve_key_dialer.xml
index 018bee8..83eb2cf 100644
--- a/res/layout-finger/twelve_key_dialer.xml
+++ b/res/layout-finger/twelve_key_dialer.xml
@@ -25,9 +25,8 @@
<!-- TODO: Use a textAppearance to control the display of the number -->
<EditText android:id="@+id/digits"
android:layout_width="fill_parent"
- android:layout_height="66dip"
+ android:layout_height="67dip"
android:layout_marginBottom="6dip"
- android:layout_marginTop="1dip"
android:gravity="center"
android:maxLines="1"
android:scrollHorizontally="true"
@@ -42,42 +41,7 @@
<include layout="@layout/dialpad" />
<!-- Horizontal row of buttons (Voicemail + DialButton + Delete.) -->
- <LinearLayout android:id="@+id/voicemailAndDialAndDelete"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:layout_gravity="center_horizontal"
- android:layout_marginBottom="6dip"
- android:orientation="horizontal">
-
- <!-- Onscreen "Voicemail" button -->
- <ImageButton android:id="@+id/voicemailButton"
- android:layout_width="90dip"
- android:layout_height="52dip"
- android:layout_gravity="center_vertical"
- android:state_enabled="false"
- android:background="@drawable/btn_dial_voicemail"
- android:src="@drawable/ic_dial_action_voice_mail" />
-
- <!-- Onscreen "Dial" button, used on all platforms by
- default. Its usage can be disabled using resources (see
- config.xml.) -->
- <ImageButton android:id="@+id/dialButton"
- android:layout_width="116dip"
- android:layout_height="52dip"
- android:layout_gravity="center_vertical"
- android:state_enabled="false"
- android:background="@drawable/btn_dial_action"
- android:src="@drawable/ic_dial_action_call" />
-
- <!-- Onscreen "Backspace/Delete" button -->
- <ImageButton android:id="@+id/deleteButton"
- android:layout_width="90dip"
- android:layout_height="52dip"
- android:layout_gravity="center_vertical"
- android:state_enabled="false"
- android:background="@drawable/btn_dial_delete"
- android:src="@drawable/ic_dial_action_delete" />
- </LinearLayout>
+ <include layout="@layout/voicemail_dial_delete" />
<!-- "Dialpad chooser" UI, shown only when the user brings up the
Dialer while a call is already in progress.
diff --git a/res/layout-finger/voicemail_dial_delete.xml b/res/layout-finger/voicemail_dial_delete.xml
new file mode 100644
index 0000000..1aa2ac4
--- /dev/null
+++ b/res/layout-finger/voicemail_dial_delete.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Horizontal row of buttons (Voicemail + DialButton + Delete.) -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/voicemailAndDialAndDelete"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="6dip"
+ android:orientation="horizontal">
+
+ <!-- Onscreen "Voicemail" button.
+ The width is 75 (from the mocks) + 12 of padding from the
+ 9patch, total is 87.
+ -->
+ <ImageButton android:id="@+id/voicemailButton"
+ android:layout_width="87dip"
+ android:layout_height="50dip"
+ android:layout_gravity="center_vertical"
+ android:state_enabled="false"
+ android:background="@drawable/btn_dial_voicemail"
+ android:src="@drawable/ic_dial_action_voice_mail" />
+
+ <!-- Onscreen "Dial" button, used on all platforms by
+ default. Its usage can be disabled using resources (see
+ config.xml.) -->
+ <ImageButton android:id="@+id/dialButton"
+ android:layout_width="116dip"
+ android:layout_height="50dip"
+ android:layout_gravity="center_vertical"
+ android:state_enabled="false"
+ android:background="@drawable/btn_dial_action"
+ android:src="@drawable/ic_dial_action_call" />
+
+ <!-- Onscreen "Backspace/Delete" button
+ The width is 75 (from the mocks) + 12 of padding from the
+ 9patch, total is 87.
+ -->
+ <ImageButton android:id="@+id/deleteButton"
+ android:layout_width="87dip"
+ android:layout_height="50dip"
+ android:layout_gravity="center_vertical"
+ android:state_enabled="false"
+ android:background="@drawable/btn_dial_delete"
+ android:src="@drawable/ic_dial_action_delete" />
+</LinearLayout>
+
diff --git a/res/layout-land-finger/twelve_key_dialer.xml b/res/layout-land-finger/twelve_key_dialer.xml
index 11ec8d6..8c66ff3 100644
--- a/res/layout-land-finger/twelve_key_dialer.xml
+++ b/res/layout-land-finger/twelve_key_dialer.xml
@@ -26,7 +26,7 @@
<EditText android:id="@+id/digits"
android:layout_width="fill_parent"
android:layout_height="66dip"
- android:layout_marginBottom="6dip"
+ android:layout_marginBottom="50dip"
android:layout_marginTop="1dip"
android:gravity="center"
android:maxLines="1"
@@ -39,42 +39,7 @@
/>
<!-- Horizontal row of buttons (Voicemail + DialButton + Delete.) -->
- <LinearLayout android:id="@+id/voicemailAndDialAndDelete"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:layout_gravity="center_horizontal"
- android:layout_marginBottom="6dip"
- android:orientation="horizontal">
-
- <!-- Onscreen "Voicemail" button -->
- <ImageButton android:id="@+id/voicemailButton"
- android:layout_width="90dip"
- android:layout_height="52dip"
- android:layout_gravity="center_vertical"
- android:state_enabled="false"
- android:background="@drawable/btn_dial_voicemail"
- android:src="@drawable/ic_dial_action_voice_mail" />
-
- <!-- Onscreen "Dial" button, used on all platforms by
- default. Its usage can be disabled using resources (see
- config.xml.) -->
- <ImageButton android:id="@+id/dialButton"
- android:layout_width="116dip"
- android:layout_height="52dip"
- android:layout_gravity="center_vertical"
- android:state_enabled="false"
- android:background="@drawable/btn_dial_action"
- android:src="@drawable/ic_dial_action_call" />
-
- <!-- Onscreen "Backspace/Delete" button -->
- <ImageButton android:id="@+id/deleteButton"
- android:layout_width="90dip"
- android:layout_height="52dip"
- android:layout_gravity="center_vertical"
- android:state_enabled="false"
- android:background="@drawable/btn_dial_delete"
- android:src="@drawable/ic_dial_action_delete" />
- </LinearLayout>
+ <include layout="@layout/voicemail_dial_delete" />
<!-- "Dialpad chooser" UI, shown only when the user brings up the
Dialer while a call is already in progress.
diff --git a/res/layout-long-finger/dialpad.xml b/res/layout-long-finger/dialpad.xml
new file mode 100644
index 0000000..036c4fa
--- /dev/null
+++ b/res/layout-long-finger/dialpad.xml
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Dialpad in the Contact app.
+ Tall screen version with taller buttons.
+ -->
+
+<com.android.contacts.ButtonGridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/dialpad"
+ android:paddingLeft="7dp"
+ android:paddingRight="7dp"
+ android:paddingTop="6dp"
+ android:paddingBottom="6dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+
+>
+ <ImageButton android:id="@+id/one"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_1_no_vm"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_one"
+ />
+
+ <ImageButton android:id="@+id/two"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_2"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_two"
+ />
+
+ <ImageButton android:id="@+id/three"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_3"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_three"
+ />
+
+ <ImageButton android:id="@+id/four"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_4"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_four"
+ />
+
+ <ImageButton android:id="@+id/five"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_5"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_five"
+ />
+
+ <ImageButton android:id="@+id/six"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_6"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_six"
+ />
+
+ <ImageButton android:id="@+id/seven"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_7"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_seven"
+ />
+
+ <ImageButton android:id="@+id/eight"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_8"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_eight"
+ />
+
+ <ImageButton android:id="@+id/nine"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_9"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_nine"
+ />
+
+ <ImageButton android:id="@+id/star"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_star"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_star"
+ />
+
+ <ImageButton android:id="@+id/zero"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_0"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_zero"
+ />
+
+ <ImageButton android:id="@+id/pound"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_pound"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_pound"
+ />
+</com.android.contacts.ButtonGridLayout>
diff --git a/res/layout-long-finger/twelve_key_dialer.xml b/res/layout-long-finger/twelve_key_dialer.xml
new file mode 100644
index 0000000..77f471e
--- /dev/null
+++ b/res/layout-long-finger/twelve_key_dialer.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/top"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+>
+
+ <!-- Text field above the keypad where the digits are displayed -->
+ <!-- TODO: Use a textAppearance to control the display of the number -->
+ <EditText android:id="@+id/digits"
+ android:layout_width="fill_parent"
+ android:layout_height="74dip"
+ android:layout_marginBottom="20dip"
+ android:gravity="center"
+ android:maxLines="1"
+ android:scrollHorizontally="true"
+ android:textSize="34sp"
+ android:freezesText="true"
+ android:background="@drawable/btn_dial_textfield"
+ android:textColor="@color/dialer_button_text"
+ android:focusableInTouchMode="false"
+ />
+
+ <!-- Keypad section -->
+ <include layout="@layout/dialpad" />
+
+ <!-- Horizontal row of buttons (Voicemail + DialButton + Delete.) -->
+ <include layout="@layout/voicemail_dial_delete" />
+
+ <!-- "Dialpad chooser" UI, shown only when the user brings up the
+ Dialer while a call is already in progress.
+ When this UI is visible, the other Dialer elements
+ (the textfield/button and the dialpad) are hidden. -->
+ <ListView android:id="@+id/dialpadChooser"
+ android:layout_width="fill_parent"
+ android:layout_height="1dip"
+ android:layout_weight="1"
+ />
+
+</LinearLayout>
diff --git a/res/layout-long-finger/voicemail_dial_delete.xml b/res/layout-long-finger/voicemail_dial_delete.xml
new file mode 100644
index 0000000..58c482b
--- /dev/null
+++ b/res/layout-long-finger/voicemail_dial_delete.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Horizontal row of buttons (Voicemail + DialButton + Delete.)
+ Tall screen version with taller buttons.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/voicemailAndDialAndDelete"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="24dip"
+ android:orientation="horizontal">
+
+ <!-- Onscreen "Voicemail" button -->
+ <ImageButton android:id="@+id/voicemailButton"
+ android:layout_width="87dip"
+ android:layout_height="58dip"
+ android:layout_gravity="center_vertical"
+ android:state_enabled="false"
+ android:background="@drawable/btn_dial_voicemail"
+ android:src="@drawable/ic_dial_action_voice_mail" />
+
+ <!-- Onscreen "Dial" button, used on all platforms by
+ default. Its usage can be disabled using resources (see
+ config.xml.) -->
+ <ImageButton android:id="@+id/dialButton"
+ android:layout_width="116dip"
+ android:layout_height="58dip"
+ android:layout_gravity="center_vertical"
+ android:state_enabled="false"
+ android:background="@drawable/btn_dial_action"
+ android:src="@drawable/ic_dial_action_call" />
+
+ <!-- Onscreen "Backspace/Delete" button -->
+ <ImageButton android:id="@+id/deleteButton"
+ android:layout_width="87dip"
+ android:layout_height="58dip"
+ android:layout_gravity="center_vertical"
+ android:state_enabled="false"
+ android:background="@drawable/btn_dial_delete"
+ android:src="@drawable/ic_dial_action_delete" />
+</LinearLayout>
+
diff --git a/res/layout-long-land-finger/twelve_key_dialer.xml b/res/layout-long-land-finger/twelve_key_dialer.xml
new file mode 100644
index 0000000..618792a
--- /dev/null
+++ b/res/layout-long-land-finger/twelve_key_dialer.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/top"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+>
+
+ <!-- Text field above the keypad where the digits are displayed -->
+ <!-- TODO: Use a textAppearance to control the display of the number -->
+ <EditText android:id="@+id/digits"
+ android:layout_width="fill_parent"
+ android:layout_height="74dip"
+ android:layout_marginBottom="30dip"
+ android:layout_marginTop="1dip"
+ android:gravity="center"
+ android:maxLines="1"
+ android:scrollHorizontally="true"
+ android:textSize="34sp"
+ android:freezesText="true"
+ android:background="@drawable/btn_dial_textfield"
+ android:textColor="@color/dialer_button_text"
+ android:hint="@string/dialerKeyboardHintText"
+ />
+
+ <!-- Horizontal row of buttons (Voicemail + DialButton + Delete.) -->
+ <include layout="@layout/voicemail_dial_delete" />
+
+ <!-- "Dialpad chooser" UI, shown only when the user brings up the
+ Dialer while a call is already in progress.
+ When this UI is visible, the other Dialer elements
+ (the textfield and button) are hidden. -->
+ <ListView android:id="@+id/dialpadChooser"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:footerDividersEnabled="true"
+ />
+
+</LinearLayout>
diff --git a/res/layout/act_display_groups.xml b/res/layout/act_display_groups.xml
new file mode 100644
index 0000000..5ee93e7
--- /dev/null
+++ b/res/layout/act_display_groups.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+ android:fillViewport="true">
+
+ <ExpandableListView
+ android:id="@android:id/list"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1" />
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ style="@android:style/ButtonBar">
+
+ <Button
+ android:id="@+id/btn_done"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/menu_done" />
+
+ <Button
+ android:id="@+id/btn_discard"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/menu_doNotSave" />
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 4b0d4ee..2b3c3fc 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"Přezdívka"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"Organizace"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"Webové stránky"</string>
- <string name="type_home" msgid="1228039089996938949">"Domů"</string>
- <string name="type_mobile" msgid="4202799691295960532">"Mobil"</string>
- <string name="type_work" msgid="9046581192178244575">"Práce"</string>
- <string name="type_fax_work" msgid="7056833051776335751">"Pracovní fax"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"Domácí fax"</string>
- <string name="type_pager" msgid="6971533430192661440">"Pager"</string>
- <string name="type_other" msgid="357858743316072535">"Ostatní"</string>
- <string name="type_custom" msgid="546891906059234753">"Vlastní"</string>
<string name="type_short_home" msgid="7770424864090605384">"D"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
<string name="type_short_work" msgid="4925330752504537861">"P"</string>
<string name="type_short_pager" msgid="2613818970827594238">"P"</string>
<string name="type_short_other" msgid="5669407180177236769">"O"</string>
- <string name="type_home_2" msgid="7576604544326827279">"Domů 2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"Práce 2"</string>
- <string name="type_car" msgid="1882297602515019816">"Auto"</string>
- <string name="type_company_main" msgid="1757801178953730800">"Firma (hlavní)"</string>
- <string name="type_mms" msgid="7575994898038669673">"MMS"</string>
- <string name="type_radio" msgid="7376516830366758196">"Radiostanice"</string>
- <string name="type_assistant" msgid="4838160907811639910">"Asistent"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"AIM"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"Yahoo"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Google Talk"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"Sekundární podrobnosti"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"Primární jméno"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"Vytvořit kontakt na základě účtu"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"Volat pracovní fax"</string>
<string name="call_fax_home" msgid="8342175628887571876">"Volat domácí fax"</string>
<string name="call_pager" msgid="9003902812293983281">"Volat pager"</string>
- <string name="call_other" msgid="5605584621798108205">"Volat ostatní"</string>
<string name="call_custom" msgid="7756571794763171802">"Volat kontakt <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="call_home_2" msgid="310203419023725540">"Volat domů 2"</string>
- <string name="call_work_2" msgid="4403999777434987049">"Volat do práce 2"</string>
<string name="call_car" msgid="3280537320306436445">"Volat do auta"</string>
<string name="call_company_main" msgid="6105120947138711257">"Volat firmu (hlavní)"</string>
<string name="call_mms" msgid="6274041545876221437">"Volat MMS"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"Poslat SMS na pager"</string>
<string name="sms_other" msgid="5131921487474531617">"Poslat SMS na ostatní"</string>
<string name="sms_custom" msgid="5932736853732191825">"Poslat SMS na <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"Poslat SMS domů 2"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"Poslat SMS do práce 2"</string>
<string name="sms_car" msgid="7444227058437359641">"Poslat SMS do auta"</string>
<string name="sms_company_main" msgid="118970873419678087">"Poslat SMS do firmy (hlavní)"</string>
<string name="sms_mms" msgid="4069352461380762677">"Poslat SMS na číslo MMS"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"Chatovat pomocí Google Talk"</string>
<string name="chat_icq" msgid="8438405386153745775">"Chatovat pomocí ICQ"</string>
<string name="chat_jabber" msgid="7561444230307829609">"Chatovat pomocí Jabberu"</string>
- <string name="chat_other" msgid="6023619161453269469">"Chat"</string>
<string name="postal_street" msgid="8133143961580058972">"Ulice"</string>
<string name="postal_pobox" msgid="4431938829180269821">"Číslo poštovní schránky"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"Čtvrť"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 3dffcd9..88d3563 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"Kaldenavn"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisation"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"Websted"</string>
- <string name="type_home" msgid="1228039089996938949">"Start"</string>
- <string name="type_mobile" msgid="4202799691295960532">"Mobil"</string>
- <string name="type_work" msgid="9046581192178244575">"Arbejde"</string>
- <string name="type_fax_work" msgid="7056833051776335751">"Arbejdsfax"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"Hjemmefax"</string>
- <string name="type_pager" msgid="6971533430192661440">"Personsøger"</string>
- <string name="type_other" msgid="357858743316072535">"Andre"</string>
- <string name="type_custom" msgid="546891906059234753">"Tilpasset"</string>
<string name="type_short_home" msgid="7770424864090605384">"H"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
<string name="type_short_work" msgid="4925330752504537861">"O"</string>
<string name="type_short_pager" msgid="2613818970827594238">"P"</string>
<string name="type_short_other" msgid="5669407180177236769">"O"</string>
- <string name="type_home_2" msgid="7576604544326827279">"Hjem 2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"Arbejde 2"</string>
- <string name="type_car" msgid="1882297602515019816">"Bil"</string>
- <string name="type_company_main" msgid="1757801178953730800">"Virksomhed (hovednummer)"</string>
- <string name="type_mms" msgid="7575994898038669673">"MMS"</string>
- <string name="type_radio" msgid="7376516830366758196">"Radio"</string>
- <string name="type_assistant" msgid="4838160907811639910">"Assistent"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"AIM"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"Yahoo"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Google Talk"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"Sekundære detaljer"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"Primærnavn"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"Opret kontaktperson under konto"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"Ring til arbejdsfax"</string>
<string name="call_fax_home" msgid="8342175628887571876">"Ring til hjemmefax"</string>
<string name="call_pager" msgid="9003902812293983281">"Ring til personsøger"</string>
- <string name="call_other" msgid="5605584621798108205">"Ring til øvrige"</string>
<string name="call_custom" msgid="7756571794763171802">"Ring til <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="call_home_2" msgid="310203419023725540">"Ring til hjem 2"</string>
- <string name="call_work_2" msgid="4403999777434987049">"Ring til arbejde 2"</string>
<string name="call_car" msgid="3280537320306436445">"Ring til bil"</string>
<string name="call_company_main" msgid="6105120947138711257">"Ring til arbejde (hovednummer)"</string>
<string name="call_mms" msgid="6274041545876221437">"Ring til MMS"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"Sms til personsøger"</string>
<string name="sms_other" msgid="5131921487474531617">"Sms til anden"</string>
<string name="sms_custom" msgid="5932736853732191825">"Tekst <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"Sms til hjem 2"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"Sms til arbejde 2"</string>
<string name="sms_car" msgid="7444227058437359641">"Sms til bil"</string>
<string name="sms_company_main" msgid="118970873419678087">"Sms til arbejde (hovednummer)"</string>
<string name="sms_mms" msgid="4069352461380762677">"Sms til MMS"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"Chat ved hjælp af Google Talk"</string>
<string name="chat_icq" msgid="8438405386153745775">"Chat ved hjælp af ICQ"</string>
<string name="chat_jabber" msgid="7561444230307829609">"Chat ved hjælp af Jabber"</string>
- <string name="chat_other" msgid="6023619161453269469">"chat"</string>
<string name="postal_street" msgid="8133143961580058972">"Gade"</string>
<string name="postal_pobox" msgid="4431938829180269821">"Postboks"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"Nabolag"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index d3ddaf3..b45e33a 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"Alias"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"Firma/Organisation"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"Website"</string>
- <string name="type_home" msgid="1228039089996938949">"Privat"</string>
- <string name="type_mobile" msgid="4202799691295960532">"Mobil"</string>
- <string name="type_work" msgid="9046581192178244575">"Arbeit"</string>
- <string name="type_fax_work" msgid="7056833051776335751">"Fax (Arbeit)"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"Fax (privat)"</string>
- <string name="type_pager" msgid="6971533430192661440">"Pager"</string>
- <string name="type_other" msgid="357858743316072535">"Andere"</string>
- <string name="type_custom" msgid="546891906059234753">"Benutzerdefiniert"</string>
<string name="type_short_home" msgid="7770424864090605384">"P"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
<string name="type_short_work" msgid="4925330752504537861">"A"</string>
<string name="type_short_pager" msgid="2613818970827594238">"P"</string>
<string name="type_short_other" msgid="5669407180177236769">"S"</string>
- <string name="type_home_2" msgid="7576604544326827279">"Privat 2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"Arbeit 2"</string>
- <string name="type_car" msgid="1882297602515019816">"Auto"</string>
- <string name="type_company_main" msgid="1757801178953730800">"Firma (Hauptnummer)"</string>
- <string name="type_mms" msgid="7575994898038669673">"MMS"</string>
- <string name="type_radio" msgid="7376516830366758196">"Radio"</string>
- <string name="type_assistant" msgid="4838160907811639910">"Assistent"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"AIM"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"Yahoo"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Google Talk"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"Sekundäre Details"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"Hauptname"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"Neuen Kontakt unter Konto erstellen"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"Anruf (Fax, Arbeit)"</string>
<string name="call_fax_home" msgid="8342175628887571876">"Faxanruf (privat)"</string>
<string name="call_pager" msgid="9003902812293983281">"Anruf (Pager)"</string>
- <string name="call_other" msgid="5605584621798108205">"Anruf (sonstige)"</string>
<string name="call_custom" msgid="7756571794763171802">"<xliff:g id="CUSTOM">%s</xliff:g> anrufen"</string>
- <string name="call_home_2" msgid="310203419023725540">"Anruf (privat 2)"</string>
- <string name="call_work_2" msgid="4403999777434987049">"Anruf (Arbeit 2)"</string>
<string name="call_car" msgid="3280537320306436445">"Anruf (Auto)"</string>
<string name="call_company_main" msgid="6105120947138711257">"Anruf (Firmenhauptnummer)"</string>
<string name="call_mms" msgid="6274041545876221437">"Anruf (MMS)"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"Text-Pager"</string>
<string name="sms_other" msgid="5131921487474531617">"Text (sonstige)"</string>
<string name="sms_custom" msgid="5932736853732191825">"Text <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"Text (privat 2)"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"Text (Arbeit 2)"</string>
<string name="sms_car" msgid="7444227058437359641">"Text (Auto)"</string>
<string name="sms_company_main" msgid="118970873419678087">"Text (Firmenhauptnummer)"</string>
<string name="sms_mms" msgid="4069352461380762677">"Text (MMS)"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"Chat über Google Talk"</string>
<string name="chat_icq" msgid="8438405386153745775">"Chat über ICQ"</string>
<string name="chat_jabber" msgid="7561444230307829609">"Chat über Jabber"</string>
- <string name="chat_other" msgid="6023619161453269469">"Chat"</string>
<string name="postal_street" msgid="8133143961580058972">"Straße"</string>
<string name="postal_pobox" msgid="4431938829180269821">"Postfach"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"Nachbarschaft"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 3618afa..ce6be87 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"Ψευδώνυμο"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"Οργανισμός"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"Ιστότοπος"</string>
- <string name="type_home" msgid="1228039089996938949">"Οικία"</string>
- <string name="type_mobile" msgid="4202799691295960532">"Κινητές συσκευές"</string>
- <string name="type_work" msgid="9046581192178244575">"Εργασία"</string>
- <string name="type_fax_work" msgid="7056833051776335751">"Φαξ εργασίας"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"Φαξ οικίας"</string>
- <string name="type_pager" msgid="6971533430192661440">"Βομβητής"</string>
- <string name="type_other" msgid="357858743316072535">"Άλλο"</string>
- <string name="type_custom" msgid="546891906059234753">"Προσαρμοσμένο"</string>
<string name="type_short_home" msgid="7770424864090605384">"Ο"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"Κ"</string>
<string name="type_short_work" msgid="4925330752504537861">"Ε"</string>
<string name="type_short_pager" msgid="2613818970827594238">"Β"</string>
<string name="type_short_other" msgid="5669407180177236769">"Α"</string>
- <string name="type_home_2" msgid="7576604544326827279">"Οικία 2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"Εργασία 2"</string>
- <string name="type_car" msgid="1882297602515019816">"Αυτοκίνητο"</string>
- <string name="type_company_main" msgid="1757801178953730800">"Κύρια εταιρική γραμμή"</string>
- <string name="type_mms" msgid="7575994898038669673">"MMS"</string>
- <string name="type_radio" msgid="7376516830366758196">"Πομπός"</string>
- <string name="type_assistant" msgid="4838160907811639910">"Βοηθός"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"AIM"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"Yahoo"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Google Talk"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"Δευτερεύουσες λεπτομέρειες"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"Κύριο όνομα"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"Δημιουργία επαφής\nστον λογαριασμό"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"Κλήση φαξ εργασίας"</string>
<string name="call_fax_home" msgid="8342175628887571876">"Κλήση φαξ οικίας"</string>
<string name="call_pager" msgid="9003902812293983281">"Κλήση βομβητή"</string>
- <string name="call_other" msgid="5605584621798108205">"Κλήση άλλο"</string>
<string name="call_custom" msgid="7756571794763171802">"Κλήση <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="call_home_2" msgid="310203419023725540">"Κλήση οικίας 2"</string>
- <string name="call_work_2" msgid="4403999777434987049">"Κλήση εργασίας 2"</string>
<string name="call_car" msgid="3280537320306436445">"Κλήση τηλεφώνου αυτοκινήτου"</string>
<string name="call_company_main" msgid="6105120947138711257">"Κλήση κύριας εταιρικής γραμμής"</string>
<string name="call_mms" msgid="6274041545876221437">"Κλήση MMS"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"Αποστολή μηνύματος κειμένου προς βομβητή"</string>
<string name="sms_other" msgid="5131921487474531617">"Αποστολή μηνύματος κειμένου προς άλλο"</string>
<string name="sms_custom" msgid="5932736853732191825">"Αποστολή μηνύματος κειμένου προς <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"Αποστολή μηνύματος κειμένου προς οικία 2"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"Αποστολή μηνύματος κειμένου προς εργασία 2"</string>
<string name="sms_car" msgid="7444227058437359641">"Αποστολή μηνύματος κειμένου προς τηλέφωνο αυτοκινήτου"</string>
<string name="sms_company_main" msgid="118970873419678087">"Αποστολή μηνύματος κειμένου προς κύρια εταιρική γραμμή"</string>
<string name="sms_mms" msgid="4069352461380762677">"Αποστολή μηνύματος κειμένου ως MMS"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"Συζήτηση μέσω Google Talk"</string>
<string name="chat_icq" msgid="8438405386153745775">"Συζήτηση μέσω ICQ"</string>
<string name="chat_jabber" msgid="7561444230307829609">"Συζήτηση μέσω Jabber"</string>
- <string name="chat_other" msgid="6023619161453269469">"Συζήτηση"</string>
<string name="postal_street" msgid="8133143961580058972">"Οδός"</string>
<string name="postal_pobox" msgid="4431938829180269821">"Ταχυδρομική θυρίδα"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"Γειτονιά"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 64e356d..d051af8 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"Apodo"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"Organización"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"Sitio web"</string>
- <string name="type_home" msgid="1228039089996938949">"Página principal"</string>
- <string name="type_mobile" msgid="4202799691295960532">"Celular"</string>
- <string name="type_work" msgid="9046581192178244575">"Trabajo"</string>
- <string name="type_fax_work" msgid="7056833051776335751">"Fax laboral"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"Fax personal"</string>
- <string name="type_pager" msgid="6971533430192661440">"Localizador"</string>
- <string name="type_other" msgid="357858743316072535">"Otros"</string>
- <string name="type_custom" msgid="546891906059234753">"Personalizado"</string>
<string name="type_short_home" msgid="7770424864090605384">"H"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"Lun."</string>
<string name="type_short_work" msgid="4925330752504537861">"Mié."</string>
<string name="type_short_pager" msgid="2613818970827594238">"P"</string>
<string name="type_short_other" msgid="5669407180177236769">"Oct."</string>
- <string name="type_home_2" msgid="7576604544326827279">"Página principal 2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"Trabajo 2"</string>
- <string name="type_car" msgid="1882297602515019816">"Auto"</string>
- <string name="type_company_main" msgid="1757801178953730800">"Empresa principal"</string>
- <string name="type_mms" msgid="7575994898038669673">"de MMS"</string>
- <string name="type_radio" msgid="7376516830366758196">"Radio"</string>
- <string name="type_assistant" msgid="4838160907811639910">"Asistente"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"AIM"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"Yahoo"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Google Talk"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"Detalles secundarios"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"Nombre principal"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"Crear contacto según la cuenta"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"Llamar al fax del trabajo"</string>
<string name="call_fax_home" msgid="8342175628887571876">"Llamar al fax personal"</string>
<string name="call_pager" msgid="9003902812293983281">"Llamar a localizador"</string>
- <string name="call_other" msgid="5605584621798108205">"Llamar a otro"</string>
<string name="call_custom" msgid="7756571794763171802">"Llamar a <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="call_home_2" msgid="310203419023725540">"Llamar al hogar 2"</string>
- <string name="call_work_2" msgid="4403999777434987049">"Llamar al trabajo 2"</string>
<string name="call_car" msgid="3280537320306436445">"Llamar al auto"</string>
<string name="call_company_main" msgid="6105120947138711257">"Llamar empresa principal"</string>
<string name="call_mms" msgid="6274041545876221437">"Llamar a MMS"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"Enviar texto a localizador"</string>
<string name="sms_other" msgid="5131921487474531617">"Enviar texto a otro"</string>
<string name="sms_custom" msgid="5932736853732191825">"Texto <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"Enviar texto al hogar 2"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"Enviar texto al trabajo 2"</string>
<string name="sms_car" msgid="7444227058437359641">"Enviar texto a auto"</string>
<string name="sms_company_main" msgid="118970873419678087">"Enviar texto a empresa principal"</string>
<string name="sms_mms" msgid="4069352461380762677">"Enviar texto MMS"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"Chat mediante Google Talk"</string>
<string name="chat_icq" msgid="8438405386153745775">"Chat mediante ICQ"</string>
<string name="chat_jabber" msgid="7561444230307829609">"Chat mediante Jabber"</string>
- <string name="chat_other" msgid="6023619161453269469">"Chat"</string>
<string name="postal_street" msgid="8133143961580058972">"Dirección postal"</string>
<string name="postal_pobox" msgid="4431938829180269821">"Apartado postal"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"Barrio"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index bcc032b..ad45fb6 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"Seudónimo"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"Organización"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"Sitio web"</string>
- <string name="type_home" msgid="1228039089996938949">"Casa"</string>
- <string name="type_mobile" msgid="4202799691295960532">"Móvil"</string>
- <string name="type_work" msgid="9046581192178244575">"Trabajo"</string>
- <string name="type_fax_work" msgid="7056833051776335751">"Fax del trabajo"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"Fax de casa"</string>
- <string name="type_pager" msgid="6971533430192661440">"Buscapersonas"</string>
- <string name="type_other" msgid="357858743316072535">"Otro"</string>
- <string name="type_custom" msgid="546891906059234753">"Personalizar"</string>
<string name="type_short_home" msgid="7770424864090605384">"H"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
<string name="type_short_work" msgid="4925330752504537861">"W"</string>
<string name="type_short_pager" msgid="2613818970827594238">"P"</string>
<string name="type_short_other" msgid="5669407180177236769">"O"</string>
- <string name="type_home_2" msgid="7576604544326827279">"Casa 2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"Trabajo 2"</string>
- <string name="type_car" msgid="1882297602515019816">"Coche"</string>
- <string name="type_company_main" msgid="1757801178953730800">"Teléfono principal de la empresa"</string>
- <string name="type_mms" msgid="7575994898038669673">"MMS"</string>
- <string name="type_radio" msgid="7376516830366758196">"Radio"</string>
- <string name="type_assistant" msgid="4838160907811639910">"Asistente"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"MI de AOL"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"Yahoo!"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Google Talk"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"Información secundaria"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"Nombre principal"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"Crear contacto en la cuenta"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"Llamar al fax del trabajo"</string>
<string name="call_fax_home" msgid="8342175628887571876">"Llamar a fax de casa"</string>
<string name="call_pager" msgid="9003902812293983281">"Llamar a buscapersonas"</string>
- <string name="call_other" msgid="5605584621798108205">"Llamar a otro"</string>
<string name="call_custom" msgid="7756571794763171802">"Llamar a <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="call_home_2" msgid="310203419023725540">"Llamar a casa 2"</string>
- <string name="call_work_2" msgid="4403999777434987049">"Llamar al trabajo 2"</string>
<string name="call_car" msgid="3280537320306436445">"Llamar al coche"</string>
<string name="call_company_main" msgid="6105120947138711257">"Llamar al teléfono principal de la empresa"</string>
<string name="call_mms" msgid="6274041545876221437">"Llamar a MMS"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"Enviar un mensaje de texto al buscapersonas"</string>
<string name="sms_other" msgid="5131921487474531617">"Enviar un mensaje de texto a otro"</string>
<string name="sms_custom" msgid="5932736853732191825">"Enviar un mensaje de texto a <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"Enviar un mensaje de texto a casa 2"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"Enviar SMS a trabajo 2"</string>
<string name="sms_car" msgid="7444227058437359641">"Enviar un mensaje de texto al coche"</string>
<string name="sms_company_main" msgid="118970873419678087">"Enviar un mensaje de texto al teléfono principal de la empresa"</string>
<string name="sms_mms" msgid="4069352461380762677">"Enviar un mensaje de texto a MMS"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"Chatear con Google Talk"</string>
<string name="chat_icq" msgid="8438405386153745775">"Chatear con ICQ"</string>
<string name="chat_jabber" msgid="7561444230307829609">"Chatear con Jabber"</string>
- <string name="chat_other" msgid="6023619161453269469">"Chat"</string>
<string name="postal_street" msgid="8133143961580058972">"Calle"</string>
<string name="postal_pobox" msgid="4431938829180269821">"Apartado postal"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"Vecindario"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 51fa4d2..26b026b 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"Pseudo"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisation"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"Site Web"</string>
- <string name="type_home" msgid="1228039089996938949">"Domicile"</string>
- <string name="type_mobile" msgid="4202799691295960532">"Mobile"</string>
- <string name="type_work" msgid="9046581192178244575">"Bureau"</string>
- <string name="type_fax_work" msgid="7056833051776335751">"Télécopie bureau"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"Télécopie domicile"</string>
- <string name="type_pager" msgid="6971533430192661440">"Téléavertisseur"</string>
- <string name="type_other" msgid="357858743316072535">"Autre"</string>
- <string name="type_custom" msgid="546891906059234753">"Personnalisé"</string>
<string name="type_short_home" msgid="7770424864090605384">"D"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
<string name="type_short_work" msgid="4925330752504537861">"B"</string>
<string name="type_short_pager" msgid="2613818970827594238">"T"</string>
<string name="type_short_other" msgid="5669407180177236769">"A"</string>
- <string name="type_home_2" msgid="7576604544326827279">"Domicile 2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"Bureau 2"</string>
- <string name="type_car" msgid="1882297602515019816">"Voiture"</string>
- <string name="type_company_main" msgid="1757801178953730800">"Société (principal)"</string>
- <string name="type_mms" msgid="7575994898038669673">"MMS"</string>
- <string name="type_radio" msgid="7376516830366758196">"Radio"</string>
- <string name="type_assistant" msgid="4838160907811639910">"Assistant"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"AIM"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"Yahoo"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Google Talk"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"Détails secondaires"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"Nom principal"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"Créer un contact sous le compte"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"Composer télécopie (bureau)"</string>
<string name="call_fax_home" msgid="8342175628887571876">"Composer fax (domicile)"</string>
<string name="call_pager" msgid="9003902812293983281">"Appeler téléavertisseur"</string>
- <string name="call_other" msgid="5605584621798108205">"Appeler autre"</string>
<string name="call_custom" msgid="7756571794763171802">"Appeler <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="call_home_2" msgid="310203419023725540">"Appeler domicile 2"</string>
- <string name="call_work_2" msgid="4403999777434987049">"Appeler bureau 2"</string>
<string name="call_car" msgid="3280537320306436445">"Appeler voiture"</string>
<string name="call_company_main" msgid="6105120947138711257">"Appeler société (principal)"</string>
<string name="call_mms" msgid="6274041545876221437">"Appeler MMS"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"Envoyer un SMS vers téléavertisseur"</string>
<string name="sms_other" msgid="5131921487474531617">"Envoyer un SMS à autre"</string>
<string name="sms_custom" msgid="5932736853732191825">"Envoyer un SMS à <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"Envoyer un SMS au domicile 2"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"Envoyer un SMS au bureau 2"</string>
<string name="sms_car" msgid="7444227058437359641">"Envoyer un SMS vers voiture"</string>
<string name="sms_company_main" msgid="118970873419678087">"Envoyer un SMS à société (principal)"</string>
<string name="sms_mms" msgid="4069352461380762677">"Envoyer un MMS"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"Chatter via Google Talk"</string>
<string name="chat_icq" msgid="8438405386153745775">"Chatter via ICQ"</string>
<string name="chat_jabber" msgid="7561444230307829609">"Chatter via Jabber"</string>
- <string name="chat_other" msgid="6023619161453269469">"Chat"</string>
<string name="postal_street" msgid="8133143961580058972">"Rue"</string>
<string name="postal_pobox" msgid="4431938829180269821">"Boîte postale"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"Voisinage"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 3807dd9..5797d61 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"Nickname"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"Organizzazione"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"Sito web"</string>
- <string name="type_home" msgid="1228039089996938949">"Casa"</string>
- <string name="type_mobile" msgid="4202799691295960532">"Cellulare"</string>
- <string name="type_work" msgid="9046581192178244575">"Ufficio"</string>
- <string name="type_fax_work" msgid="7056833051776335751">"Fax ufficio"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"Fax casa"</string>
- <string name="type_pager" msgid="6971533430192661440">"Cercapersone"</string>
- <string name="type_other" msgid="357858743316072535">"Altro"</string>
- <string name="type_custom" msgid="546891906059234753">"Personalizzato"</string>
<string name="type_short_home" msgid="7770424864090605384">"H"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
<string name="type_short_work" msgid="4925330752504537861">"W"</string>
<string name="type_short_pager" msgid="2613818970827594238">"P"</string>
<string name="type_short_other" msgid="5669407180177236769">"O"</string>
- <string name="type_home_2" msgid="7576604544326827279">"Casa 2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"Ufficio 2"</string>
- <string name="type_car" msgid="1882297602515019816">"Automobile"</string>
- <string name="type_company_main" msgid="1757801178953730800">"Azienda, principale"</string>
- <string name="type_mms" msgid="7575994898038669673">"MMS"</string>
- <string name="type_radio" msgid="7376516830366758196">"Segnale cellulare"</string>
- <string name="type_assistant" msgid="4838160907811639910">"Assistente"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"AIM"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"Yahoo"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Google Talk"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"Dettagli secondari"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"Nome principale"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"Crea contatto sotto account"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"Chiama n. fax ufficio"</string>
<string name="call_fax_home" msgid="8342175628887571876">"Chiama n. fax casa"</string>
<string name="call_pager" msgid="9003902812293983281">"Chiama n. cercapersone"</string>
- <string name="call_other" msgid="5605584621798108205">"Chiama altro"</string>
<string name="call_custom" msgid="7756571794763171802">"Chiama n. <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="call_home_2" msgid="310203419023725540">"Chiama n. casa 2"</string>
- <string name="call_work_2" msgid="4403999777434987049">"Chiama n. ufficio 2"</string>
<string name="call_car" msgid="3280537320306436445">"Chiama n. automobile"</string>
<string name="call_company_main" msgid="6105120947138711257">"Chiama n. azienda, principale"</string>
<string name="call_mms" msgid="6274041545876221437">"Chiama n. MMS"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"Invia SMS a n. cercapersone"</string>
<string name="sms_other" msgid="5131921487474531617">"Invia SMS ad altro"</string>
<string name="sms_custom" msgid="5932736853732191825">"Invia SMS a n. <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"Invia SMS a n. casa 2"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"Invia SMS a n. ufficio 2"</string>
<string name="sms_car" msgid="7444227058437359641">"Invia SMS a n. automobile"</string>
<string name="sms_company_main" msgid="118970873419678087">"Invia SMS a n. azienda, principale"</string>
<string name="sms_mms" msgid="4069352461380762677">"Invia SMS a n. MMS"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"Chatta tramite Google Talk"</string>
<string name="chat_icq" msgid="8438405386153745775">"Chatta tramite ICQ"</string>
<string name="chat_jabber" msgid="7561444230307829609">"Chatta tramite Jabber"</string>
- <string name="chat_other" msgid="6023619161453269469">"Chatta"</string>
<string name="postal_street" msgid="8133143961580058972">"Indirizzo postale"</string>
<string name="postal_pobox" msgid="4431938829180269821">"Casella postale"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"Zona"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index ceb30a1..1e539dd 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"ニックネーム"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"所属"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"ウェブサイト"</string>
- <string name="type_home" msgid="1228039089996938949">"自宅"</string>
- <string name="type_mobile" msgid="4202799691295960532">"携帯"</string>
- <string name="type_work" msgid="9046581192178244575">"勤務先"</string>
- <string name="type_fax_work" msgid="7056833051776335751">"FAX(勤務先)"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"FAX(自宅)"</string>
- <string name="type_pager" msgid="6971533430192661440">"ポケベル"</string>
- <string name="type_other" msgid="357858743316072535">"その他"</string>
- <string name="type_custom" msgid="546891906059234753">"カスタム"</string>
<string name="type_short_home" msgid="7770424864090605384">"自宅"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"携帯"</string>
<string name="type_short_work" msgid="4925330752504537861">"勤務先"</string>
<string name="type_short_pager" msgid="2613818970827594238">"ポケベル"</string>
<string name="type_short_other" msgid="5669407180177236769">"その他"</string>
- <string name="type_home_2" msgid="7576604544326827279">"自宅2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"勤務先2"</string>
- <string name="type_car" msgid="1882297602515019816">"クルマ"</string>
- <string name="type_company_main" msgid="1757801178953730800">"会社代表番号"</string>
- <string name="type_mms" msgid="7575994898038669673">"MMS"</string>
- <string name="type_radio" msgid="7376516830366758196">"無線"</string>
- <string name="type_assistant" msgid="4838160907811639910">"アシスタント"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"AIM"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"Yahoo"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Googleトーク"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"その他の情報"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"メインの名前"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"アカウントに連絡先を作成"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"勤務先FAXに発信"</string>
<string name="call_fax_home" msgid="8342175628887571876">"自宅のFAXに発信"</string>
<string name="call_pager" msgid="9003902812293983281">"ポケベルに発信"</string>
- <string name="call_other" msgid="5605584621798108205">"その他に発信"</string>
<string name="call_custom" msgid="7756571794763171802">"<xliff:g id="CUSTOM">%s</xliff:g>に発信"</string>
- <string name="call_home_2" msgid="310203419023725540">"自宅2に発信"</string>
- <string name="call_work_2" msgid="4403999777434987049">"勤務先2に発信"</string>
<string name="call_car" msgid="3280537320306436445">"クルマに発信"</string>
<string name="call_company_main" msgid="6105120947138711257">"会社代表番号に発信"</string>
<string name="call_mms" msgid="6274041545876221437">"MMSに発信"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"ポケベルにSMS"</string>
<string name="sms_other" msgid="5131921487474531617">"その他にSMS"</string>
<string name="sms_custom" msgid="5932736853732191825">"<xliff:g id="CUSTOM">%s</xliff:g>にSMS"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"自宅2にSMS"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"勤務先2にSMS"</string>
<string name="sms_car" msgid="7444227058437359641">"クルマにSMS"</string>
<string name="sms_company_main" msgid="118970873419678087">"会社代表番号にSMS"</string>
<string name="sms_mms" msgid="4069352461380762677">"MMSにSMS"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"Googleトークでチャット"</string>
<string name="chat_icq" msgid="8438405386153745775">"ICQでチャット"</string>
<string name="chat_jabber" msgid="7561444230307829609">"Jabberでチャット"</string>
- <string name="chat_other" msgid="6023619161453269469">"チャット"</string>
<string name="postal_street" msgid="8133143961580058972">"番地"</string>
<string name="postal_pobox" msgid="4431938829180269821">"私書箱"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"近所"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 80ac629..cd45ca9 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"닉네임"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"조직"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"웹사이트"</string>
- <string name="type_home" msgid="1228039089996938949">"집"</string>
- <string name="type_mobile" msgid="4202799691295960532">"모바일"</string>
- <string name="type_work" msgid="9046581192178244575">"직장"</string>
- <string name="type_fax_work" msgid="7056833051776335751">"직장 팩스"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"집(팩스)"</string>
- <string name="type_pager" msgid="6971533430192661440">"호출기"</string>
- <string name="type_other" msgid="357858743316072535">"기타"</string>
- <string name="type_custom" msgid="546891906059234753">"맞춤설정"</string>
<string name="type_short_home" msgid="7770424864090605384">"H"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
<string name="type_short_work" msgid="4925330752504537861">"W"</string>
<string name="type_short_pager" msgid="2613818970827594238">"P"</string>
<string name="type_short_other" msgid="5669407180177236769">"O"</string>
- <string name="type_home_2" msgid="7576604544326827279">"집 2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"직장 2"</string>
- <string name="type_car" msgid="1882297602515019816">"카폰"</string>
- <string name="type_company_main" msgid="1757801178953730800">"회사 기본전화"</string>
- <string name="type_mms" msgid="7575994898038669673">"MMS"</string>
- <string name="type_radio" msgid="7376516830366758196">"무선통신"</string>
- <string name="type_assistant" msgid="4838160907811639910">"비서"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"AIM"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"Yahoo"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Google 토크"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"보조 세부정보"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"기본 이름"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"계정에서 연락처 만들기"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"직장 팩스로 전화걸기"</string>
<string name="call_fax_home" msgid="8342175628887571876">"집 팩스로 전화걸기"</string>
<string name="call_pager" msgid="9003902812293983281">"호출기로 전화걸기"</string>
- <string name="call_other" msgid="5605584621798108205">"기타 연락처로 전화걸기"</string>
<string name="call_custom" msgid="7756571794763171802">"<xliff:g id="CUSTOM">%s</xliff:g>(으)로 전화걸기"</string>
- <string name="call_home_2" msgid="310203419023725540">"집 2로 전화걸기"</string>
- <string name="call_work_2" msgid="4403999777434987049">"직장 2로 전화걸기"</string>
<string name="call_car" msgid="3280537320306436445">"카폰으로 전화걸기"</string>
<string name="call_company_main" msgid="6105120947138711257">"회사 기본전화로 전화걸기"</string>
<string name="call_mms" msgid="6274041545876221437">"MMS로 전화걸기"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"호출기로 문자 보내기"</string>
<string name="sms_other" msgid="5131921487474531617">"기타 연락처로 문자 보내기"</string>
<string name="sms_custom" msgid="5932736853732191825">"문자(<xliff:g id="CUSTOM">%s</xliff:g>)"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"집 2로 문자 보내기"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"직장 2로 문자 보내기"</string>
<string name="sms_car" msgid="7444227058437359641">"카폰으로 문자 보내기"</string>
<string name="sms_company_main" msgid="118970873419678087">"회사 기본전화로 문자 보내기"</string>
<string name="sms_mms" msgid="4069352461380762677">"MMS로 문자 보내기"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"Google 토크로 채팅"</string>
<string name="chat_icq" msgid="8438405386153745775">"ICQ로 채팅"</string>
<string name="chat_jabber" msgid="7561444230307829609">"Jabber로 채팅"</string>
- <string name="chat_other" msgid="6023619161453269469">"채팅"</string>
<string name="postal_street" msgid="8133143961580058972">"번지"</string>
<string name="postal_pobox" msgid="4431938829180269821">"사서함"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"인근 지역"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index b5a5bc0..57d17c1 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"Kallenavn"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisering"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"Nettsted"</string>
- <string name="type_home" msgid="1228039089996938949">"Privat"</string>
- <string name="type_mobile" msgid="4202799691295960532">"Mobil"</string>
- <string name="type_work" msgid="9046581192178244575">"Arbeid"</string>
- <string name="type_fax_work" msgid="7056833051776335751">"Send faks (arbeid)"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"Send faks (privat)"</string>
- <string name="type_pager" msgid="6971533430192661440">"Personsøker"</string>
- <string name="type_other" msgid="357858743316072535">"Annen"</string>
- <string name="type_custom" msgid="546891906059234753">"Tilpasset"</string>
<string name="type_short_home" msgid="7770424864090605384">"H"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
<string name="type_short_work" msgid="4925330752504537861">"W"</string>
<string name="type_short_pager" msgid="2613818970827594238">"P"</string>
<string name="type_short_other" msgid="5669407180177236769">"O"</string>
- <string name="type_home_2" msgid="7576604544326827279">"Privat 2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"Arbeid 2"</string>
- <string name="type_car" msgid="1882297602515019816">"Bil"</string>
- <string name="type_company_main" msgid="1757801178953730800">"Firma (sentralbord)"</string>
- <string name="type_mms" msgid="7575994898038669673">"MMS"</string>
- <string name="type_radio" msgid="7376516830366758196">"Radio"</string>
- <string name="type_assistant" msgid="4838160907811639910">"Assistent"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"AIM"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"Yahoo"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Google Talk"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"Andre detaljer"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"Hovednavn"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"Opprett kontakt under konto"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"Anrop faks (arbeid)"</string>
<string name="call_fax_home" msgid="8342175628887571876">"Anrop faks (privat)"</string>
<string name="call_pager" msgid="9003902812293983281">"Ring personsøker"</string>
- <string name="call_other" msgid="5605584621798108205">"Ring (annet)"</string>
<string name="call_custom" msgid="7756571794763171802">"Ring <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="call_home_2" msgid="310203419023725540">"Ring (privat 2)"</string>
- <string name="call_work_2" msgid="4403999777434987049">"Ring (arbeid 2)"</string>
<string name="call_car" msgid="3280537320306436445">"Ring (bil)"</string>
<string name="call_company_main" msgid="6105120947138711257">"Ring firma (sentralbord)"</string>
<string name="call_mms" msgid="6274041545876221437">"Ring MMS"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"Send SMS (personsøker)"</string>
<string name="sms_other" msgid="5131921487474531617">"Send SMS (annet)"</string>
<string name="sms_custom" msgid="5932736853732191825">"Send SMS (<xliff:g id="CUSTOM">%s</xliff:g>)"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"Send SMS (privat) 2"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"Send SMS (arbeid 2)"</string>
<string name="sms_car" msgid="7444227058437359641">"Send SMS (bil)"</string>
<string name="sms_company_main" msgid="118970873419678087">"Send SMS til firma (sentralbord)"</string>
<string name="sms_mms" msgid="4069352461380762677">"Send MMS"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"Nettprat med Google Talk"</string>
<string name="chat_icq" msgid="8438405386153745775">"Nettprat med ICQ"</string>
<string name="chat_jabber" msgid="7561444230307829609">"Nettprat med Jabber"</string>
- <string name="chat_other" msgid="6023619161453269469">"Nettprat"</string>
<string name="postal_street" msgid="8133143961580058972">"Gate"</string>
<string name="postal_pobox" msgid="4431938829180269821">"Postboks"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"Nabolag"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 8a0964a..d2ca5b3 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"Bijnaam"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisatie"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"Website"</string>
- <string name="type_home" msgid="1228039089996938949">"Thuis"</string>
- <string name="type_mobile" msgid="4202799691295960532">"Mobiel"</string>
- <string name="type_work" msgid="9046581192178244575">"Werk"</string>
- <string name="type_fax_work" msgid="7056833051776335751">"Fax werk"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"Fax thuis"</string>
- <string name="type_pager" msgid="6971533430192661440">"Pager"</string>
- <string name="type_other" msgid="357858743316072535">"Overig"</string>
- <string name="type_custom" msgid="546891906059234753">"Aangepast"</string>
<string name="type_short_home" msgid="7770424864090605384">"T"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
<string name="type_short_work" msgid="4925330752504537861">"W"</string>
<string name="type_short_pager" msgid="2613818970827594238">"P"</string>
<string name="type_short_other" msgid="5669407180177236769">"O"</string>
- <string name="type_home_2" msgid="7576604544326827279">"Thuis 2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"Werk 2"</string>
- <string name="type_car" msgid="1882297602515019816">"Auto"</string>
- <string name="type_company_main" msgid="1757801178953730800">"Hoofdkantoor"</string>
- <string name="type_mms" msgid="7575994898038669673">"MMS"</string>
- <string name="type_radio" msgid="7376516830366758196">"Radio"</string>
- <string name="type_assistant" msgid="4838160907811639910">"Assistent"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"AIM"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"Yahoo"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Google Talk"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"Secundaire gegevens"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"Primaire naam"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"Contact in account maken"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"Bellen naar fax werk"</string>
<string name="call_fax_home" msgid="8342175628887571876">"Bellen naar huisfax"</string>
<string name="call_pager" msgid="9003902812293983281">"Bellen naar pager"</string>
- <string name="call_other" msgid="5605584621798108205">"Bellen naar overig"</string>
<string name="call_custom" msgid="7756571794763171802">"<xliff:g id="CUSTOM">%s</xliff:g> bellen"</string>
- <string name="call_home_2" msgid="310203419023725540">"Bellen naar huis 2"</string>
- <string name="call_work_2" msgid="4403999777434987049">"Bellen naar werk 2"</string>
<string name="call_car" msgid="3280537320306436445">"Bellen naar autotelefoon"</string>
<string name="call_company_main" msgid="6105120947138711257">"Bellen naar hoofdkantoor"</string>
<string name="call_mms" msgid="6274041545876221437">"Bellen via MMS"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"Sms\'en naar pager"</string>
<string name="sms_other" msgid="5131921487474531617">"Sms\'en naar overig"</string>
<string name="sms_custom" msgid="5932736853732191825">"Sms\'en naar <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"Sms\'en naar huis 2"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"Sms\'en naar werk 2"</string>
<string name="sms_car" msgid="7444227058437359641">"Sms\'en naar autotelefoon"</string>
<string name="sms_company_main" msgid="118970873419678087">"Sms\'en naar hoofdkantoor"</string>
<string name="sms_mms" msgid="4069352461380762677">"Sms\'en via MMS"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"Chatten via Google Talk"</string>
<string name="chat_icq" msgid="8438405386153745775">"Chatten via ICQ"</string>
<string name="chat_jabber" msgid="7561444230307829609">"Chatten via Jabber"</string>
- <string name="chat_other" msgid="6023619161453269469">"Chat"</string>
<string name="postal_street" msgid="8133143961580058972">"Straat"</string>
<string name="postal_pobox" msgid="4431938829180269821">"Postbus"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"Wijk"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index fcd4c63..02797d5 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"Pseudonim"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"Organizacja"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"Adres witryny"</string>
- <string name="type_home" msgid="1228039089996938949">"Domowy"</string>
- <string name="type_mobile" msgid="4202799691295960532">"Komórkowy"</string>
- <string name="type_work" msgid="9046581192178244575">"Służbowy"</string>
- <string name="type_fax_work" msgid="7056833051776335751">"Faks służbowy"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"Faks domowy"</string>
- <string name="type_pager" msgid="6971533430192661440">"Pager"</string>
- <string name="type_other" msgid="357858743316072535">"Inny"</string>
- <string name="type_custom" msgid="546891906059234753">"Niestandardowy"</string>
<string name="type_short_home" msgid="7770424864090605384">"D"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"K"</string>
<string name="type_short_work" msgid="4925330752504537861">"S"</string>
<string name="type_short_pager" msgid="2613818970827594238">"P"</string>
<string name="type_short_other" msgid="5669407180177236769">"I"</string>
- <string name="type_home_2" msgid="7576604544326827279">"Domowy 2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"Służbowy 2"</string>
- <string name="type_car" msgid="1882297602515019816">"Samochód"</string>
- <string name="type_company_main" msgid="1757801178953730800">"Firmowy główny"</string>
- <string name="type_mms" msgid="7575994898038669673">"Wiadomość MMS"</string>
- <string name="type_radio" msgid="7376516830366758196">"Radio"</string>
- <string name="type_assistant" msgid="4838160907811639910">"Asystent"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"AIM"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"Yahoo"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Google Talk"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"Dodatkowe informacje szczegółowe"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"Nazwa główna"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"Utwórz kontakt na koncie"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"Telefon – faks służbowy"</string>
<string name="call_fax_home" msgid="8342175628887571876">"Telefon – faks domowy"</string>
<string name="call_pager" msgid="9003902812293983281">"Telefon – pager"</string>
- <string name="call_other" msgid="5605584621798108205">"Telefon – inny"</string>
<string name="call_custom" msgid="7756571794763171802">"Telefon – <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="call_home_2" msgid="310203419023725540">"Telefon – domowy 2"</string>
- <string name="call_work_2" msgid="4403999777434987049">"Telefon – służbowy 2"</string>
<string name="call_car" msgid="3280537320306436445">"Telefon – samochód"</string>
<string name="call_company_main" msgid="6105120947138711257">"Telefon – firmowy główny"</string>
<string name="call_mms" msgid="6274041545876221437">"Telefon – wiadomość MMS"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"Tekst – pager"</string>
<string name="sms_other" msgid="5131921487474531617">"Tekst – inny"</string>
<string name="sms_custom" msgid="5932736853732191825">"Tekst – <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"Tekst – domowy 2"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"Tekst – służbowy 2"</string>
<string name="sms_car" msgid="7444227058437359641">"Tekst – samochód"</string>
<string name="sms_company_main" msgid="118970873419678087">"Tekst – firmowy główny"</string>
<string name="sms_mms" msgid="4069352461380762677">"Tekst – wiadomość MMS"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"Czat w Google Talk"</string>
<string name="chat_icq" msgid="8438405386153745775">"Czat w ICQ"</string>
<string name="chat_jabber" msgid="7561444230307829609">"Czat w Jabberze"</string>
- <string name="chat_other" msgid="6023619161453269469">"Czat"</string>
<string name="postal_street" msgid="8133143961580058972">"Ulica"</string>
<string name="postal_pobox" msgid="4431938829180269821">"Skrytka pocztowa"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"Okolica"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index b25b731..5802679 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"Alcunha"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"Organização"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"Web site"</string>
- <string name="type_home" msgid="1228039089996938949">"Residência"</string>
- <string name="type_mobile" msgid="4202799691295960532">"Telemóvel"</string>
- <string name="type_work" msgid="9046581192178244575">"Emprego"</string>
- <string name="type_fax_work" msgid="7056833051776335751">"Fax do emprego"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"Fax da residência"</string>
- <string name="type_pager" msgid="6971533430192661440">"Pager"</string>
- <string name="type_other" msgid="357858743316072535">"Outro"</string>
- <string name="type_custom" msgid="546891906059234753">"Personalizado"</string>
<string name="type_short_home" msgid="7770424864090605384">"R"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"T"</string>
<string name="type_short_work" msgid="4925330752504537861">"E"</string>
<string name="type_short_pager" msgid="2613818970827594238">"P"</string>
<string name="type_short_other" msgid="5669407180177236769">"O"</string>
- <string name="type_home_2" msgid="7576604544326827279">"Residência 2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"Emprego 2"</string>
- <string name="type_car" msgid="1882297602515019816">"Automóvel"</string>
- <string name="type_company_main" msgid="1757801178953730800">"Telefone principal da empresa"</string>
- <string name="type_mms" msgid="7575994898038669673">"MMS"</string>
- <string name="type_radio" msgid="7376516830366758196">"Rádio"</string>
- <string name="type_assistant" msgid="4838160907811639910">"Assistente"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"AIM"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"Yahoo"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Google Talk"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"Detalhes secundários"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"Nome principal"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"Criar contacto subordinado à conta"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"Ligar para fax do emprego"</string>
<string name="call_fax_home" msgid="8342175628887571876">"Ligar para o fax da residência"</string>
<string name="call_pager" msgid="9003902812293983281">"Ligar para pager"</string>
- <string name="call_other" msgid="5605584621798108205">"Ligar para outros"</string>
<string name="call_custom" msgid="7756571794763171802">"Ligar para <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="call_home_2" msgid="310203419023725540">"Ligar para residência 2"</string>
- <string name="call_work_2" msgid="4403999777434987049">"Ligar para emprego 2"</string>
<string name="call_car" msgid="3280537320306436445">"Ligar para automóvel"</string>
<string name="call_company_main" msgid="6105120947138711257">"Ligar para telefone principal da empresa"</string>
<string name="call_mms" msgid="6274041545876221437">"Ligar por MMS"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"Enviar SMS para pager"</string>
<string name="sms_other" msgid="5131921487474531617">"Enviar SMS para outros"</string>
<string name="sms_custom" msgid="5932736853732191825">"Enviar SMS a <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"Enviar SMS para residência 2"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"Enviar SMS para emprego 2"</string>
<string name="sms_car" msgid="7444227058437359641">"Enviar SMS para automóvel"</string>
<string name="sms_company_main" msgid="118970873419678087">"Enviar SMS para telefone principal da empresa"</string>
<string name="sms_mms" msgid="4069352461380762677">"Enviar MMS"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"Chat através do Google Talk"</string>
<string name="chat_icq" msgid="8438405386153745775">"Chat utilizando ICQ"</string>
<string name="chat_jabber" msgid="7561444230307829609">"Chat utilizando Jabber"</string>
- <string name="chat_other" msgid="6023619161453269469">"Chat"</string>
<string name="postal_street" msgid="8133143961580058972">"Rua"</string>
<string name="postal_pobox" msgid="4431938829180269821">"Apartado"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"Vizinhança"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index ac91be0..86423f1 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"Apelido"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"Organização"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"Site"</string>
- <string name="type_home" msgid="1228039089996938949">"Página inicial"</string>
- <string name="type_mobile" msgid="4202799691295960532">"Celular"</string>
- <string name="type_work" msgid="9046581192178244575">"Trabalho"</string>
- <string name="type_fax_work" msgid="7056833051776335751">"Fax comercial"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"Fax residencial"</string>
- <string name="type_pager" msgid="6971533430192661440">"Pager"</string>
- <string name="type_other" msgid="357858743316072535">"Outros"</string>
- <string name="type_custom" msgid="546891906059234753">"Personalizado"</string>
<string name="type_short_home" msgid="7770424864090605384">"H"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
<string name="type_short_work" msgid="4925330752504537861">"W"</string>
<string name="type_short_pager" msgid="2613818970827594238">"P"</string>
<string name="type_short_other" msgid="5669407180177236769">"O"</string>
- <string name="type_home_2" msgid="7576604544326827279">"Residência 2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"Trabalho 2"</string>
- <string name="type_car" msgid="1882297602515019816">"Carro"</string>
- <string name="type_company_main" msgid="1757801178953730800">"Empresa (principal)"</string>
- <string name="type_mms" msgid="7575994898038669673">"MMS"</string>
- <string name="type_radio" msgid="7376516830366758196">"Rádio"</string>
- <string name="type_assistant" msgid="4838160907811639910">"Assistente"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"AIM"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"Yahoo"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Google Talk"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"Detalhes secundários"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"Nome principal"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"Criar contato na conta"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"Chamar fax comercial"</string>
<string name="call_fax_home" msgid="8342175628887571876">"Chamar fax residencial"</string>
<string name="call_pager" msgid="9003902812293983281">"Chamar pager"</string>
- <string name="call_other" msgid="5605584621798108205">"Chamar outros"</string>
<string name="call_custom" msgid="7756571794763171802">"Chamar <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="call_home_2" msgid="310203419023725540">"Chamar residência 2"</string>
- <string name="call_work_2" msgid="4403999777434987049">"Chamar o trabalho 2"</string>
<string name="call_car" msgid="3280537320306436445">"Chamar carro"</string>
<string name="call_company_main" msgid="6105120947138711257">"Chamar empresa (principal)"</string>
<string name="call_mms" msgid="6274041545876221437">"Chamar MMS"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"Enviar mensagem de texto para o pager"</string>
<string name="sms_other" msgid="5131921487474531617">"Enviar mensagem de texto para outras pessoas"</string>
<string name="sms_custom" msgid="5932736853732191825">"Enviar mensagem de texto para <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"Texto (residencial) 2"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"Texto (comercial) 2"</string>
<string name="sms_car" msgid="7444227058437359641">"Enviar mensagem de texto para o carro"</string>
<string name="sms_company_main" msgid="118970873419678087">"Enviar mensagem de texto para empresa (principal)"</string>
<string name="sms_mms" msgid="4069352461380762677">"Enviar texto MMS"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"Bater papo usando o Google Talk"</string>
<string name="chat_icq" msgid="8438405386153745775">"Bater papo usando o ICQ"</string>
<string name="chat_jabber" msgid="7561444230307829609">"Bater papo usando o Jabber"</string>
- <string name="chat_other" msgid="6023619161453269469">"Bate-papo"</string>
<string name="postal_street" msgid="8133143961580058972">"Rua"</string>
<string name="postal_pobox" msgid="4431938829180269821">"Caixa postal"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"Vizinhança"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 2d74e72..aa5d2f8 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"Псевдоним"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"Организация"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"Веб-сайт"</string>
- <string name="type_home" msgid="1228039089996938949">"Дом."</string>
- <string name="type_mobile" msgid="4202799691295960532">"Моб."</string>
- <string name="type_work" msgid="9046581192178244575">"Раб."</string>
- <string name="type_fax_work" msgid="7056833051776335751">"Раб. факс"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"Дом. факс"</string>
- <string name="type_pager" msgid="6971533430192661440">"Пейджер"</string>
- <string name="type_other" msgid="357858743316072535">"Другое"</string>
- <string name="type_custom" msgid="546891906059234753">"Другое"</string>
<string name="type_short_home" msgid="7770424864090605384">"Д"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"М"</string>
<string name="type_short_work" msgid="4925330752504537861">"Р"</string>
<string name="type_short_pager" msgid="2613818970827594238">"П"</string>
<string name="type_short_other" msgid="5669407180177236769">"Др"</string>
- <string name="type_home_2" msgid="7576604544326827279">"Дом. 2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"Раб. 2"</string>
- <string name="type_car" msgid="1882297602515019816">"Автомоб."</string>
- <string name="type_company_main" msgid="1757801178953730800">"Раб., осн."</string>
- <string name="type_mms" msgid="7575994898038669673">"MMS"</string>
- <string name="type_radio" msgid="7376516830366758196">"Радиотелефон"</string>
- <string name="type_assistant" msgid="4838160907811639910">"Помощник"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"AIM"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"Yahoo"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Google Talk"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"Дополнительные подробности"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"Основное имя"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"Создать контакт в аккаунте"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"Позвонить (раб. факс)"</string>
<string name="call_fax_home" msgid="8342175628887571876">"Позвонить (дом. факс)"</string>
<string name="call_pager" msgid="9003902812293983281">"Позвонить (пейджер)"</string>
- <string name="call_other" msgid="5605584621798108205">"Позвонить (другое)"</string>
<string name="call_custom" msgid="7756571794763171802">"Позвонить (<xliff:g id="CUSTOM">%s</xliff:g>)"</string>
- <string name="call_home_2" msgid="310203419023725540">"Позвонить (дом. 2)"</string>
- <string name="call_work_2" msgid="4403999777434987049">"Позвонить (раб. 2)"</string>
<string name="call_car" msgid="3280537320306436445">"Позвонить (автомоб.)"</string>
<string name="call_company_main" msgid="6105120947138711257">"Позвонить (раб., осн.)"</string>
<string name="call_mms" msgid="6274041545876221437">"Позвонить (MMS)"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"SMS (пейджер)"</string>
<string name="sms_other" msgid="5131921487474531617">"SMS (другое)"</string>
<string name="sms_custom" msgid="5932736853732191825">"SMS (<xliff:g id="CUSTOM">%s</xliff:g>)"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"SMS (дом. 2)"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"SMS (раб. 2)"</string>
<string name="sms_car" msgid="7444227058437359641">"SMS (автомоб.)"</string>
<string name="sms_company_main" msgid="118970873419678087">"SMS (раб., осн.)"</string>
<string name="sms_mms" msgid="4069352461380762677">"MMS"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"Чат через Google Talk"</string>
<string name="chat_icq" msgid="8438405386153745775">"Чат через ICQ"</string>
<string name="chat_jabber" msgid="7561444230307829609">"Чат через Jabber"</string>
- <string name="chat_other" msgid="6023619161453269469">"Чат"</string>
<string name="postal_street" msgid="8133143961580058972">"Улица"</string>
<string name="postal_pobox" msgid="4431938829180269821">"Почтовый ящик"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"Окружение"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index c9c48bf..50d9f8d 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"Smeknamn"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisation"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"Webbplats"</string>
- <string name="type_home" msgid="1228039089996938949">"Hem"</string>
- <string name="type_mobile" msgid="4202799691295960532">"Mobil"</string>
- <string name="type_work" msgid="9046581192178244575">"Arbete"</string>
- <string name="type_fax_work" msgid="7056833051776335751">"Arbetsfax"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"Hemfax"</string>
- <string name="type_pager" msgid="6971533430192661440">"Personsökare"</string>
- <string name="type_other" msgid="357858743316072535">"Övrigt"</string>
- <string name="type_custom" msgid="546891906059234753">"Anpassad"</string>
<string name="type_short_home" msgid="7770424864090605384">"H"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
<string name="type_short_work" msgid="4925330752504537861">"A"</string>
<string name="type_short_pager" msgid="2613818970827594238">"P"</string>
<string name="type_short_other" msgid="5669407180177236769">"A"</string>
- <string name="type_home_2" msgid="7576604544326827279">"Hem 2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"Arbete 2"</string>
- <string name="type_car" msgid="1882297602515019816">"Bil"</string>
- <string name="type_company_main" msgid="1757801178953730800">"Nummer till företag"</string>
- <string name="type_mms" msgid="7575994898038669673">"MMS"</string>
- <string name="type_radio" msgid="7376516830366758196">"Radio"</string>
- <string name="type_assistant" msgid="4838160907811639910">"Assistent"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"AIM"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"Yahoo"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Google Talk"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"Sekundära detaljer"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"Primärt namn"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"Skapa kontakt under konto"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"Ring – arbetsfax"</string>
<string name="call_fax_home" msgid="8342175628887571876">"Ring upp hemfax"</string>
<string name="call_pager" msgid="9003902812293983281">"Ring personsökare"</string>
- <string name="call_other" msgid="5605584621798108205">"Ring – annan"</string>
<string name="call_custom" msgid="7756571794763171802">"Ring <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="call_home_2" msgid="310203419023725540">"Ring hem 2"</string>
- <string name="call_work_2" msgid="4403999777434987049">"Ring arbete 2"</string>
<string name="call_car" msgid="3280537320306436445">"Ring bilen"</string>
<string name="call_company_main" msgid="6105120947138711257">"Ring företagets växel"</string>
<string name="call_mms" msgid="6274041545876221437">"Samtal – MMS"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"SMS – personsökare"</string>
<string name="sms_other" msgid="5131921487474531617">"SMS – annan"</string>
<string name="sms_custom" msgid="5932736853732191825">"Skicka SMS till <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"SMS – hem 2"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"SMS – arbete 2"</string>
<string name="sms_car" msgid="7444227058437359641">"SMS – bil"</string>
<string name="sms_company_main" msgid="118970873419678087">"SMS – jobbväxel"</string>
<string name="sms_mms" msgid="4069352461380762677">"Skicka MMS"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"Chatta med Google Talk"</string>
<string name="chat_icq" msgid="8438405386153745775">"Chatta med ICQ"</string>
<string name="chat_jabber" msgid="7561444230307829609">"Chatta med Jabber"</string>
- <string name="chat_other" msgid="6023619161453269469">"Chatt"</string>
<string name="postal_street" msgid="8133143961580058972">"Gata"</string>
<string name="postal_pobox" msgid="4431938829180269821">"Postbox"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"Område"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 1510190..c8ae19c 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"Takma ad"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"Kuruluş"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"Web sitesi"</string>
- <string name="type_home" msgid="1228039089996938949">"Ev"</string>
- <string name="type_mobile" msgid="4202799691295960532">"Mobil"</string>
- <string name="type_work" msgid="9046581192178244575">"İş"</string>
- <string name="type_fax_work" msgid="7056833051776335751">"İş Faksı"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"Ev Faksı"</string>
- <string name="type_pager" msgid="6971533430192661440">"Çağrı cihazı"</string>
- <string name="type_other" msgid="357858743316072535">"Diğer"</string>
- <string name="type_custom" msgid="546891906059234753">"Özel"</string>
<string name="type_short_home" msgid="7770424864090605384">"E"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
<string name="type_short_work" msgid="4925330752504537861">"İ"</string>
<string name="type_short_pager" msgid="2613818970827594238">"Ç"</string>
<string name="type_short_other" msgid="5669407180177236769">"D"</string>
- <string name="type_home_2" msgid="7576604544326827279">"Ev 2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"İş 2"</string>
- <string name="type_car" msgid="1882297602515019816">"Araç"</string>
- <string name="type_company_main" msgid="1757801178953730800">"Şirket Merkezi"</string>
- <string name="type_mms" msgid="7575994898038669673">"MMS"</string>
- <string name="type_radio" msgid="7376516830366758196">"Telsiz"</string>
- <string name="type_assistant" msgid="4838160907811639910">"Asistan"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"AIM"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"Yahoo"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Google Talk"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"İkincil ayrıntılar"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"Ön ad"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"Hesap altında kişi oluştur"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"Ara (iş faksı)"</string>
<string name="call_fax_home" msgid="8342175628887571876">"Ara (ev faksı)"</string>
<string name="call_pager" msgid="9003902812293983281">"Çağrı cihazını ara"</string>
- <string name="call_other" msgid="5605584621798108205">"Ara (diğer)"</string>
<string name="call_custom" msgid="7756571794763171802">"Ara (<xliff:g id="CUSTOM">%s</xliff:g>)"</string>
- <string name="call_home_2" msgid="310203419023725540">"Ara (ev 2)"</string>
- <string name="call_work_2" msgid="4403999777434987049">"Ara (iş 2)"</string>
<string name="call_car" msgid="3280537320306436445">"Ara (araç)"</string>
<string name="call_company_main" msgid="6105120947138711257">"Ara (şirket merkezi)"</string>
<string name="call_mms" msgid="6274041545876221437">"Ara (MMS)"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"Metin (çağrı cihazı)"</string>
<string name="sms_other" msgid="5131921487474531617">"Metin (diğer)"</string>
<string name="sms_custom" msgid="5932736853732191825">"Metin <xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"Metin (ev 2)"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"Metin (iş 2)"</string>
<string name="sms_car" msgid="7444227058437359641">"Metin (araç)"</string>
<string name="sms_company_main" msgid="118970873419678087">"Metin (şirket merkezi)"</string>
<string name="sms_mms" msgid="4069352461380762677">"Metin (MMS)"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"Google Talk kullanarak sohbet et"</string>
<string name="chat_icq" msgid="8438405386153745775">"ICQ kullanarak sohbet et"</string>
<string name="chat_jabber" msgid="7561444230307829609">"Jabber kullanarak sohbet et"</string>
- <string name="chat_other" msgid="6023619161453269469">"Sohbet"</string>
<string name="postal_street" msgid="8133143961580058972">"Cadde"</string>
<string name="postal_pobox" msgid="4431938829180269821">"Posta kutusu"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"Mahalle"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 937ab21..4ee3b92 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"昵称"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"组织"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"网站"</string>
- <string name="type_home" msgid="1228039089996938949">"住宅"</string>
- <string name="type_mobile" msgid="4202799691295960532">"手机"</string>
- <string name="type_work" msgid="9046581192178244575">"单位"</string>
- <string name="type_fax_work" msgid="7056833051776335751">"单位传真"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"住宅传真"</string>
- <string name="type_pager" msgid="6971533430192661440">"寻呼机"</string>
- <string name="type_other" msgid="357858743316072535">"其他"</string>
- <string name="type_custom" msgid="546891906059234753">"自定义"</string>
<string name="type_short_home" msgid="7770424864090605384">"H"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
<string name="type_short_work" msgid="4925330752504537861">"W"</string>
<string name="type_short_pager" msgid="2613818970827594238">"P"</string>
<string name="type_short_other" msgid="5669407180177236769">"O"</string>
- <string name="type_home_2" msgid="7576604544326827279">"住宅 2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"单位 2"</string>
- <string name="type_car" msgid="1882297602515019816">"车载电话"</string>
- <string name="type_company_main" msgid="1757801178953730800">"公司总机"</string>
- <string name="type_mms" msgid="7575994898038669673">"彩信"</string>
- <string name="type_radio" msgid="7376516830366758196">"无线装置"</string>
- <string name="type_assistant" msgid="4838160907811639910">"助手"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"AIM"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"雅虎"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Google Talk"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"附属详情"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"主名称"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"在帐户下创建联系人"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"呼叫单位传真"</string>
<string name="call_fax_home" msgid="8342175628887571876">"呼叫住宅传真"</string>
<string name="call_pager" msgid="9003902812293983281">"呼叫寻呼机"</string>
- <string name="call_other" msgid="5605584621798108205">"呼叫“其他”通讯方式"</string>
<string name="call_custom" msgid="7756571794763171802">"呼叫<xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="call_home_2" msgid="310203419023725540">"呼叫住宅 2"</string>
- <string name="call_work_2" msgid="4403999777434987049">"呼叫单位 2"</string>
<string name="call_car" msgid="3280537320306436445">"呼叫车载电话"</string>
<string name="call_company_main" msgid="6105120947138711257">"呼叫公司总机"</string>
<string name="call_mms" msgid="6274041545876221437">"语音彩信"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"向寻呼机发送文字消息"</string>
<string name="sms_other" msgid="5131921487474531617">"向其他通讯工具发送文本消息"</string>
<string name="sms_custom" msgid="5932736853732191825">"向<xliff:g id="CUSTOM">%s</xliff:g>发送文本消息"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"向住宅 2 发送文本消息"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"向单位 2 发送文本消息"</string>
<string name="sms_car" msgid="7444227058437359641">"向车载电话发送文本消息"</string>
<string name="sms_company_main" msgid="118970873419678087">"向公司总机发送文本消息"</string>
<string name="sms_mms" msgid="4069352461380762677">"文本彩信"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"使用 Google Talk 聊天"</string>
<string name="chat_icq" msgid="8438405386153745775">"使用 ICQ 聊天"</string>
<string name="chat_jabber" msgid="7561444230307829609">"使用 Jabber 聊天"</string>
- <string name="chat_other" msgid="6023619161453269469">"聊天"</string>
<string name="postal_street" msgid="8133143961580058972">"街道"</string>
<string name="postal_pobox" msgid="4431938829180269821">"信箱"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"街区"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 3280ba2..e0f04cf 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -299,34 +299,11 @@
<string name="nicknameLabelsGroup" msgid="2891682101053358010">"暱稱"</string>
<string name="organizationLabelsGroup" msgid="2478611760751832035">"機構"</string>
<string name="websiteLabelsGroup" msgid="4202998982804009261">"網站"</string>
- <string name="type_home" msgid="1228039089996938949">"住家"</string>
- <string name="type_mobile" msgid="4202799691295960532">"行動裝置"</string>
- <string name="type_work" msgid="9046581192178244575">"公司"</string>
- <string name="type_fax_work" msgid="7056833051776335751">"公司傳真"</string>
- <string name="type_fax_home" msgid="5188151910627934239">"住家傳真"</string>
- <string name="type_pager" msgid="6971533430192661440">"呼叫器"</string>
- <string name="type_other" msgid="357858743316072535">"其他"</string>
- <string name="type_custom" msgid="546891906059234753">"自訂"</string>
<string name="type_short_home" msgid="7770424864090605384">"住家"</string>
<string name="type_short_mobile" msgid="1655473281466676216">"行動"</string>
<string name="type_short_work" msgid="4925330752504537861">"工作"</string>
<string name="type_short_pager" msgid="2613818970827594238">"呼叫器"</string>
<string name="type_short_other" msgid="5669407180177236769">"其他"</string>
- <string name="type_home_2" msgid="7576604544326827279">"住家 2"</string>
- <string name="type_work_2" msgid="4033954623350210826">"公司 2"</string>
- <string name="type_car" msgid="1882297602515019816">"汽車電話"</string>
- <string name="type_company_main" msgid="1757801178953730800">"公司代表號"</string>
- <string name="type_mms" msgid="7575994898038669673">"MMS"</string>
- <string name="type_radio" msgid="7376516830366758196">"無線電"</string>
- <string name="type_assistant" msgid="4838160907811639910">"助理"</string>
- <string name="type_im_aim" msgid="2227683604131341761">"AIM"</string>
- <string name="type_im_msn" msgid="5322977067527283958">"Windows Live"</string>
- <string name="type_im_yahoo" msgid="8093860976582856789">"Yahoo"</string>
- <string name="type_im_skype" msgid="7847929379814316050">"Skype"</string>
- <string name="type_im_qq" msgid="764805405209877788">"QQ"</string>
- <string name="type_im_google_talk" msgid="4019292000925519902">"Google Talk"</string>
- <string name="type_im_icq" msgid="7556014886862234019">"ICQ"</string>
- <string name="type_im_jabber" msgid="5523148125631896131">"Jabber"</string>
<string name="edit_secondary_collapse" msgid="1855127176548440583">"次要詳細資料"</string>
<string name="dialog_primary_name" msgid="5521591005692614833">"主要名稱"</string>
<string name="dialog_new_contact_account" msgid="9044704073286262197">"在帳戶下建立聯絡人"</string>
@@ -345,10 +322,7 @@
<string name="call_fax_work" msgid="7467763592359059243">"去電公司傳真"</string>
<string name="call_fax_home" msgid="8342175628887571876">"去電住家傳真"</string>
<string name="call_pager" msgid="9003902812293983281">"去電呼叫器"</string>
- <string name="call_other" msgid="5605584621798108205">"去電其他電話"</string>
<string name="call_custom" msgid="7756571794763171802">"去電<xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="call_home_2" msgid="310203419023725540">"去電住家電話 2"</string>
- <string name="call_work_2" msgid="4403999777434987049">"去電公司電話 2"</string>
<string name="call_car" msgid="3280537320306436445">"去電汽車電話"</string>
<string name="call_company_main" msgid="6105120947138711257">"去電公司代表號"</string>
<string name="call_mms" msgid="6274041545876221437">"去電 MMS"</string>
@@ -361,8 +335,6 @@
<string name="sms_pager" msgid="7730404569637015192">"傳送簡訊至呼叫器"</string>
<string name="sms_other" msgid="5131921487474531617">"傳送簡訊至其他裝置"</string>
<string name="sms_custom" msgid="5932736853732191825">"傳送簡訊至<xliff:g id="CUSTOM">%s</xliff:g>"</string>
- <string name="sms_home_2" msgid="7944150531556566287">"傳送簡訊至住家電話 2"</string>
- <string name="sms_work_2" msgid="1652790306127907938">"傳送簡訊至公司電話 2"</string>
<string name="sms_car" msgid="7444227058437359641">"傳送簡訊至汽車電話"</string>
<string name="sms_company_main" msgid="118970873419678087">"傳送簡訊至公司代表號"</string>
<string name="sms_mms" msgid="4069352461380762677">"傳送 MMS 簡訊"</string>
@@ -385,7 +357,6 @@
<string name="chat_gtalk" msgid="981575737258117697">"使用 Google Talk 進行即時通訊"</string>
<string name="chat_icq" msgid="8438405386153745775">"使用 ICQ 進行即時通訊"</string>
<string name="chat_jabber" msgid="7561444230307829609">"使用 Jabber 進行即時通訊"</string>
- <string name="chat_other" msgid="6023619161453269469">"使用其他即時通訊進行即時通訊"</string>
<string name="postal_street" msgid="8133143961580058972">"街道"</string>
<string name="postal_pobox" msgid="4431938829180269821">"郵政信箱"</string>
<string name="postal_neighborhood" msgid="1450783874558956739">"鄰"</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 0742250..4361fd4 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -20,4 +20,5 @@
<!-- The height of the ScrollingTabWidget -->
<dimen name="tab_height">40dip</dimen>
+ <dimen name="account_name_height">25dip</dimen>
</resources>
diff --git a/res/values/ids.xml b/res/values/ids.xml
index 1af6162..cf1d419 100644
--- a/res/values/ids.xml
+++ b/res/values/ids.xml
@@ -42,8 +42,7 @@
<item type="id" name="dialog_error_with_message" />
<!-- For ExportVCard -->
- <item type="id" name="dialog_confirm_export_vcard" />
- <item type="id" name="dialog_exporting_vcard" />
+ <item type="id" name="dialog_export_confirmation" />
<item type="id" name="dialog_fail_to_export_with_reason" />
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index e181ab3..da7bb88 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -130,7 +130,7 @@
<!-- Menu item that joins an aggregate with another aggregate -->
<string name="menu_joinAggregate">Join</string>
-
+
<!-- Menu item to toggle the tabs that show where the contact data comes from. -->
<string name="menu_showSources">Show sources</string>
<string name="menu_hideSources">Hide sources</string>
@@ -138,6 +138,12 @@
<!-- Activity title for the Join Contact list -->
<string name="titleJoinAggregate">Join contact</string>
+ <!-- Heading of the Join Contact screen -->
+ <string name="titleJoinContactDataWith">Join contacts</string>
+
+ <!-- Info blurb on the Join Contact screen -->
+ <string name="blurbJoinContactDataWith">Select the contact you want to join with <xliff:g id="name">%s</xliff:g>.</string>
+
<!-- List separator for the Join Contact list: Suggestions -->
<string name="separatorJoinAggregateSuggestions">Suggestions</string>
@@ -272,10 +278,10 @@
<string name="customLabelPickerTitle">Custom label name</string>
<!-- The menu item to open the list of groups to display -->
- <string name="menu_displayGroup">Display groups</string>
+ <string name="menu_displayGroup">Display options</string>
<!-- Title of activity that lets user pick which contact groups to display -->
- <string name="displayGroups">Display groups</string>
+ <string name="displayGroups">Display options</string>
<!-- The menu item that leads to the settings for contact syncing -->
<string name="syncGroupPreference">Edit sync groups</string>
@@ -301,6 +307,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 contacts list is empty while displaying results after searching contacts -->
+ <string name="noMatchingContacts">No matching contacts found.</string>
+
<!-- The text displayed when the contacts list is empty while displaying only contacts that have phone numbers -->
<string name="noContactsWithPhoneNumbers">No contacts with phone numbers.</string>
@@ -324,7 +333,7 @@
<string name="showFilterPhonesDescrip">Only display contacts that have phone numbers</string>
<!-- The header over the list of all contacts groups -->
- <string name="headerContactGroups">Contact groups</string>
+ <string name="headerContactGroups">Choose contacts to display</string>
<!-- The description of a group with the total number of contacts -->
<plurals name="groupDescrip">
@@ -351,8 +360,8 @@
<!-- Displayed in a spinner dialog after the user creates a contact and it's being saved to the database -->
<string name="savingContact">Saving contact\u2026</string>
- <!-- Displayed in a spinner dialog as user changes to display groups are saved -->
- <string name="savingDisplayGroups">Saving display groups\u2026</string>
+ <!-- Displayed in a spinner dialog as user changes to display options are saved -->
+ <string name="savingDisplayGroups">Saving display options\u2026</string>
<!-- Toast displayed when a contact is created -->
<string name="contactCreatedToast">Contact created.</string>
@@ -405,6 +414,12 @@
<!-- Section header in the Edit Contacts screen for the "Add more items" button -->
<string name="listSeparatorMore_edit">More</string>
+ <!-- Displayed at the top of the contacts showing the total number of contacts visible when "Only contacts with phones" is selected -->
+ <string name="listTotalPhoneContacts"><xliff:g id="num">%s</xliff:g> contacts with phone numbers</string>
+
+ <!-- Displayed at the top of the contacts showing the total number of contacts visible when "Only contacts with phones" not selected -->
+ <string name="listTotalAllContacts"><xliff:g id="num">%s</xliff:g> contacts</string>
+
<!-- The description text for the social activity stream tab. Space is limited for this string, so the shorter the better -->
<string name="socialStreamIconLabel">Social</string>
@@ -493,7 +508,7 @@
<!-- Displayed full screen when the user has no contacts and they are displaying the My Contacts group, and contact syncing is enabled -->
<string name="noContactsHelpTextWithSync">"You don't have any contacts to display. (If you just added an account, it can take a few minutes to sync contacts.)\n\nTo add contacts, press <font fgcolor="#ffffffff"><b>Menu</b></font> and touch:\n
\n<li><font fgcolor="#ffffffff"><b>Accounts</b></font> to add or configure an account with contacts you can sync to the phone\n</li>
- \n<li><font fgcolor="#ffffffff"><b>Display groups</b></font> to change which groups of contacts are visible\n</li>
+ \n<li><font fgcolor="#ffffffff"><b>Display options</b></font> to change which contacts are visible\n</li>
\n<li><font fgcolor="#ffffffff"><b>New contact</b></font> to create a new contact from scratch\n</li>
\n<li><font fgcolor="#ffffffff"><b>Import/Export</b></font>\n</li>"
</string>
@@ -508,7 +523,7 @@
<!-- Displayed full screen when the user has no contacts and they are displaying the My Contacts group, and contact syncing is enabled, and there is no sim card (cdma) -->
<string name="noContactsNoSimHelpTextWithSync">"You don't have any contacts to display. (If you just added an account, it can take a few minutes to sync contacts.)\n\nTo add contacts, press <font fgcolor="#ffffffff"><b>Menu</b></font> and touch:\n
\n<li><font fgcolor="#ffffffff"><b>Accounts</b></font> to add or configure an account with contacts you can sync to the phone\n</li>
- \n<li><font fgcolor="#ffffffff"><b>Display groups</b></font> to change which groups of contacts are visible\n</li>
+ \n<li><font fgcolor="#ffffffff"><b>Display options</b></font> to change which contacts are visible\n</li>
\n<li><font fgcolor="#ffffffff"><b>New contact</b></font> to create a new contact from scratch\n</li>
\n<li><font fgcolor="#ffffffff"><b>Import/Export</b></font>\n</li>"
</string>
@@ -810,6 +825,12 @@
<!-- Message while reading multiple vCard files "(current number) of (total number) files" The order of "current number" and "total number" cannot be changed (like "total: (total number), current: (current number)")-->
<string name="reading_vcard_files"><xliff:g id="current_number">%s</xliff:g> of <xliff:g id="total_number">%s</xliff:g> files</string>
+ <!-- The message for exporting all contacts in the phone, without caring its Account -->
+ <string name="export_all_contacts">All contacts</string>
+
+ <!-- The message for exporting only contacts is the phone locally, which are not associated with any account -->
+ <string name="export_phone_local_only">Locally stored contacts</string>
+
<!-- The menu item that launches VCard export activity -->
<string name="export_contact_list">Export contacts</string>
@@ -825,6 +846,9 @@
<!-- Dialog message shown when exporting Contact data failed -->
<string name="exporting_contact_failed_message">Failed to export contact data.\nReason for failure: \"<xliff:g id="fail_reason">%s</xliff:g>\"</string>
+ <!-- The failed reason: "There is no exportable contact" -->
+ <string name="fail_reason_no_exportable_contact">There is no exportable contact</string>
+
<!-- The failed reason: "Too many vcard files on the SD Card" -->
<string name="fail_reason_too_many_vcard">Too many vCard files on the SD card</string>
@@ -846,6 +870,15 @@
<!-- The failed reason: "Error occured during export" -->
<string name="fail_reason_error_occurred_during_export">Error occured during export: \"<xliff:g id="exact_reason">%s</xliff:g>\"</string>
+ <!-- The error reason the vCard composer emits: "Failed to get database information" -->
+ <string name="composer_failed_to_get_database_infomation">Failed to get database information</string>
+
+ <!-- The error reason the vCard composer emits: "There is no exportable contact. You might choose un-exportable data" -->
+ <string name="composer_has_no_exportable_contact">There is no exportable contact. You might choose un-exportable data</string>
+
+ <!-- The error reason the vCard composer emits: "The vCard composer object is not correctly initialized" -->
+ <string name="composer_not_initialized">The vCard composer is not correctly initialized</string>
+
<!-- The failed reason: "Could not open a specific file" -->
<string name="fail_reason_could_not_open_file">Could not open \"<xliff:g id="file_name">%s</xliff:g>\": <xliff:g id="exact_reason">%s</xliff:g></string>
@@ -935,9 +968,12 @@
<string name="dialog_sync_add">Add sync group</string>
<string name="display_more_groups">More groups\u2026</string>
+ <!-- List title for a special contacts group that covers all contacts.-->
+ <string name="display_ungrouped">All Other Contacts</string>
+
<!-- List title for a special contacts group that covers all contacts that
- aren't members of any other group. -->
- <string name="display_ungrouped">(Ungrouped contacts)</string>
+ aren't members of any other group. -->
+ <string name="display_all_contacts">All Contacts</string>
<!-- Warning message given to users just before they remove a currently syncing
group that would also cause all ungrouped contacts to stop syncing. -->
@@ -1112,10 +1148,13 @@
<string name="name_phonetic_middle">Phonetic middle name</string>
<!-- Field title for the phonetic family name of a contact -->
<string name="name_phonetic_family">Phonetic family name</string>
-
+
<!-- The title for the action to remove a contact from an aggregated contact -->
<string name="split_label">Split</string>
<!-- The explanation of what "split" will do. This needs word-smithing. -->
<string name="split_explanation">Make this data its own contact.</string>
+
+ <!-- Formatting string for account name -->
+ <string name="account_name_format">From <xliff:g id="source" example="Gmail">%1$s</xliff:g> account: <xliff:g id="account" example="user@gmail.com">%2$s</xliff:g></string>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index ad44b34..05c0916 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -4,9 +4,9 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
-
+
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,6 +15,10 @@
-->
<resources>
+ <style name="DialtactsTheme" parent="@android:Theme">
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
<style name="MinusButton">
<item name="android:background">@drawable/btn_circle</item>
diff --git a/src/com/android/contacts/ButtonGridLayout.java b/src/com/android/contacts/ButtonGridLayout.java
index 69eed97..c3fb1d9 100644
--- a/src/com/android/contacts/ButtonGridLayout.java
+++ b/src/com/android/contacts/ButtonGridLayout.java
@@ -18,13 +18,40 @@
import android.content.Context;
import android.util.AttributeSet;
+import android.view.View.MeasureSpec;
import android.view.View;
import android.view.ViewGroup;
-import android.view.View.MeasureSpec;
+/**
+ * Create a 4x3 grid of dial buttons.
+ *
+ * It was easier and more efficient to do it this way than use
+ * standard layouts. It's perfectly fine (and actually encouraged) to
+ * use custom layouts rather than piling up standard layouts.
+ *
+ * The horizontal and vertical spacings between buttons are controlled
+ * by the amount of padding (attributes on the ButtonGridLayout element):
+ * - horizontal = left + right padding and
+ * - vertical = top + bottom padding.
+ *
+ * This class assumes that all the buttons have the same size.
+ *
+ * Invocation: onMeasure is called first by the framework to know our
+ * size. Then onLayout is invoked to layout the buttons.
+ */
+// TODO: Blindly layout the buttons w/o checking if we overrun the
+// bottom-right corner.
public class ButtonGridLayout extends ViewGroup {
+ private final int COLUMNS = 3;
+ private final int ROWS = 4;
- private final int mColumns = 3;
+ // Width and height of a button
+ private int mButtonWidth;
+ private int mButtonHeight;
+
+ // Width and height of a button + padding.
+ private int mWidthInc;
+ private int mHeightInc;
public ButtonGridLayout(Context context) {
super(context);
@@ -40,64 +67,43 @@
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ int i = 0;
int y = mPaddingTop;
- final int rows = getRows();
- final View child0 = getChildAt(0);
- final int yInc = (getHeight() - mPaddingTop - mPaddingBottom) / rows;
- final int xInc = (getWidth() - mPaddingLeft - mPaddingRight) / mColumns;
- final int childWidth = child0.getMeasuredWidth();
- final int childHeight = child0.getMeasuredHeight();
- final int xOffset = (xInc - childWidth) / 2;
- final int yOffset = (yInc - childHeight) / 2;
-
- for (int row = 0; row < rows; row++) {
+ for (int row = 0; row < ROWS; row++) {
int x = mPaddingLeft;
- for (int col = 0; col < mColumns; col++) {
- int cell = row * mColumns + col;
- if (cell >= getChildCount()) {
- break;
- }
- View child = getChildAt(cell);
- child.layout(x + xOffset, y + yOffset,
- x + xOffset + childWidth,
- y + yOffset + childHeight);
- x += xInc;
- }
- y += yInc;
- }
- }
+ for (int col = 0; col < COLUMNS; col++) {
+ View child = getChildAt(i);
- private int getRows() {
- return (getChildCount() + mColumns - 1) / mColumns;
- }
+ child.layout(x, y, x + mButtonWidth, y + mButtonHeight);
+
+ x += mWidthInc;
+ i++;
+ }
+ y += mHeightInc;
+ }
+ }
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int width = mPaddingLeft + mPaddingRight;
- int height = mPaddingTop + mPaddingBottom;
-
- // Measure the first child and get it's size
+ // Measure the first child and get it's size
View child = getChildAt(0);
child.measure(MeasureSpec.UNSPECIFIED , MeasureSpec.UNSPECIFIED);
- int childWidth = child.getMeasuredWidth();
- int childHeight = child.getMeasuredHeight();
+
// Make sure the other children are measured as well, to initialize
for (int i = 1; i < getChildCount(); i++) {
getChildAt(i).measure(MeasureSpec.UNSPECIFIED , MeasureSpec.UNSPECIFIED);
}
- // All cells are going to be the size of the first child
- width += mColumns * childWidth;
- final int finalWidth = resolveSize(width, widthMeasureSpec);
- // The vertical padding between button must be the same as the
- // horizontal one. The cumulative horizontal padding is the
- // difference between 'width' and 'finalWidth'.
- final int padding = (finalWidth - width) / mColumns;
+ // Store these to be reused in onLayout.
+ mButtonWidth = child.getMeasuredWidth();
+ mButtonHeight = child.getMeasuredHeight();
+ mWidthInc = mButtonWidth + mPaddingLeft + mPaddingRight;
+ mHeightInc = mButtonHeight + mPaddingTop + mPaddingBottom;
- height += getRows() * (childHeight + padding);
+ final int width = resolveSize(COLUMNS * mWidthInc, widthMeasureSpec);
+ final int height = resolveSize(ROWS * mHeightInc, heightMeasureSpec);
- final int finalHeight = resolveSize(height, heightMeasureSpec);
- setMeasuredDimension(finalWidth, finalHeight);
+ setMeasuredDimension(width, height);
}
}
diff --git a/src/com/android/contacts/Collapser.java b/src/com/android/contacts/Collapser.java
index db1da1f..3872dfd 100644
--- a/src/com/android/contacts/Collapser.java
+++ b/src/com/android/contacts/Collapser.java
@@ -39,38 +39,42 @@
*/
public interface Collapsible<T> {
public boolean collapseWith(T t);
- public String getCollapseKey();
+ public boolean shouldCollapseWith(T t);
}
/**
* Collapses a list of Collapsible items into a list of collapsed items. Items are collapsed
- * if they produce equal collapseKeys {@Link Collapsible#getCollapseKey()}, and are collapsed
- * through the {@Link Collapsible#doCollapseWith(Object)} function implemented by the data item.
+ * if {@link Collapsible#shouldCollapseWith(Object) return strue, and are collapsed
+ * through the {@Link Collapsible#collapseWith(Object)} function implemented by the data item.
*
* @param list ArrayList of Objects of type <T extends Collapsible<T>> to be collapsed.
*/
public static <T extends Collapsible<T>> void collapseList(ArrayList<T> list) {
- HashMap<String, T> collapseMap = new HashMap<String, T>();
- ArrayList<String> collapseKeys = new ArrayList<String>();
int listSize = list.size();
- for (int j = 0; j < listSize; j++) {
- T entry = list.get(j);
- String collapseKey = entry.getCollapseKey();
- if (!collapseMap.containsKey(collapseKey)) {
- collapseMap.put(collapseKey, entry);
- collapseKeys.add(collapseKey);
- } else {
- collapseMap.get(collapseKey).collapseWith(entry);
+
+ for (int i = 0; i < listSize; i++) {
+ T iItem = list.get(i);
+ if (iItem != null) {
+ for (int j = i + 1; j < listSize; j++) {
+ T jItem = list.get(j);
+ if (jItem != null) {
+ if (iItem.shouldCollapseWith(jItem)) {
+ iItem.collapseWith(jItem);
+ list.set(j, null);
+ }
+ }
+ }
}
}
- if (collapseKeys.size() < listSize) {
- list.clear();
- Iterator<String> itr = collapseKeys.iterator();
- while (itr.hasNext()) {
- list.add(collapseMap.get(itr.next()));
+ // Remove the null items
+ Iterator<T> itr = list.iterator();
+ while (itr.hasNext()) {
+ if (itr.next() == null) {
+ itr.remove();
}
}
+
}
}
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index cddcffe..aa6654d 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -16,11 +16,10 @@
package com.android.contacts;
-import com.android.contacts.model.ContactsSource;
-import com.android.contacts.model.GoogleSource;
import com.android.contacts.model.Sources;
import com.android.contacts.ui.DisplayGroupsActivity;
import com.android.contacts.ui.DisplayGroupsActivity.Prefs;
+import com.android.contacts.util.AccountSelectionUtil;
import com.android.contacts.util.Constants;
import android.accounts.Account;
@@ -117,8 +116,13 @@
/**
* Displays a list of contacts. Usually is embedded into the ContactsActivity.
*/
-public final class ContactsListActivity extends ListActivity implements
+public class ContactsListActivity extends ListActivity implements
View.OnCreateContextMenuListener, View.OnClickListener {
+
+ public static class JoinContactActivity extends ContactsListActivity {
+
+ }
+
private static final String TAG = "ContactsListActivity";
private static final boolean ENABLE_ACTION_ICON_OVERLAYS = true;
@@ -156,6 +160,14 @@
*/
public static final String EXTRA_AGGREGATE_ID =
"com.android.contacts.action.AGGREGATE_ID";
+ /**
+ * Used with {@link #JOIN_AGGREGATE} to give it the name of the aggregation target.
+ * <p>
+ * Type: STRING
+ */
+ public static final String EXTRA_AGGREGATE_NAME =
+ "com.android.contacts.action.AGGREGATE_NAME";
+
public static final String AUTHORITIES_FILTER_KEY = "authorities";
@@ -175,11 +187,13 @@
static final int MODE_MASK_SHOW_CALL_BUTTON = 0x02000000;
/** Mask to disable fasttrack (images will show as normal images) */
static final int MODE_MASK_DISABLE_FASTTRACK = 0x01000000;
+ /** Mask to show the total number of contacts at the top */
+ static final int MODE_MASK_SHOW_NUMBER_OF_CONTACTS = 0x00800000;
/** Unknown mode */
static final int MODE_UNKNOWN = 0;
/** Default mode */
- static final int MODE_DEFAULT = 4 | MODE_MASK_SHOW_PHOTOS;
+ static final int MODE_DEFAULT = 4 | MODE_MASK_SHOW_PHOTOS | MODE_MASK_SHOW_NUMBER_OF_CONTACTS;
/** Custom mode */
static final int MODE_CUSTOM = 8;
/** Show all starred contacts */
@@ -234,7 +248,7 @@
Contacts.DISPLAY_NAME, // 1
Contacts.STARRED, //2
Contacts.TIMES_CONTACTED, //3
- Presence.PRESENCE_STATUS, //4
+ Contacts.CONTACT_PRESENCE, //4
Contacts.PHOTO_ID, //5
Contacts.HAS_PHONE_NUMBER, //6
Contacts.LOOKUP_KEY, //7
@@ -301,15 +315,6 @@
static final String KEY_PICKER_MODE = "picker_mode";
- /*
- * TODO: Will be commented in the really near future. Similar commented out codes will be done.
- * These are for make vCard exporter code understard two additional options:
- * "export contacts in the phone only" and
- * "export all contacts without caring Account information".
- * static final Account sExportPhoneLocalAccount;
- * static final Account sExportAllAccount;
- */
-
private ContactItemListAdapter mAdapter;
int mMode = MODE_DEFAULT;
@@ -351,8 +356,6 @@
*/
private String mQueryData;
- private VCardExporter mVCardExporter;
-
private static final String CLAUSE_ONLY_VISIBLE = Contacts.IN_VISIBLE_GROUP + "=1";
private static final String CLAUSE_ONLY_PHONES = Contacts.HAS_PHONE_NUMBER + "=1";
@@ -362,8 +365,6 @@
static {
sContactsIdMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sContactsIdMatcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID);
- /*sExportPhoneLocalAccount = new Account("Phone-local Account", "phone-local");
- sExportAllAccount = new Account("All account", "all");*/
}
private class DeleteClickListener implements DialogInterface.OnClickListener {
@@ -394,8 +395,6 @@
final String action = intent.getAction();
mMode = MODE_UNKNOWN;
- setContentView(R.layout.contacts_list_content);
-
Log.i(TAG, "Called with action: " + action);
if (UI.LIST_DEFAULT.equals(action)) {
mMode = MODE_DEFAULT;
@@ -541,6 +540,7 @@
return;
}
+
if (JOIN_AGGREGATE.equals(action)) {
mMode = MODE_JOIN_CONTACT;
mQueryAggregateId = intent.getLongExtra(EXTRA_AGGREGATE_ID, -1);
@@ -550,16 +550,30 @@
setResult(RESULT_CANCELED);
finish();
}
-
- setTitle(R.string.titleJoinAggregate);
}
if (mMode == MODE_UNKNOWN) {
mMode = MODE_DEFAULT;
}
+ if (mMode == MODE_JOIN_CONTACT) {
+ setContentView(R.layout.contacts_list_content_join);
+ TextView blurbView = (TextView)findViewById(R.id.join_contact_blurb);
+ String contactName = intent.getStringExtra(EXTRA_AGGREGATE_NAME);
+ if (contactName == null) {
+ contactName = "";
+ }
+
+ String blurb = getString(R.string.blurbJoinContactDataWith, contactName);
+ blurbView.setText(blurb);
+
+ } else {
+ setContentView(R.layout.contacts_list_content);
+ }
+
// Setup the UI
final ListView list = getListView();
+
// Tell list view to not show dividers. We'll do it ourself so that we can *not* show
// them when an A-Z headers is visible.
list.setDividerHeight(0);
@@ -625,6 +639,10 @@
}
private void setEmptyText() {
+ if (mMode == MODE_JOIN_CONTACT) {
+ return;
+ }
+
TextView empty = (TextView) findViewById(R.id.emptyText);
int gravity = Gravity.NO_GRAVITY;
@@ -633,6 +651,8 @@
gravity = Gravity.CENTER;
} else if (mMode == MODE_STREQUENT || mMode == MODE_STARRED) {
empty.setText(getText(R.string.noFavoritesHelpText));
+ } else if (mMode == MODE_QUERY) {
+ empty.setText(getText(R.string.noMatchingContacts));
} else {
boolean hasSim = ((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE))
.hasIccCard();
@@ -747,6 +767,7 @@
// be there and show up while the new query is happening. After the async query finished
// in response to onRestart() setLoading(false) will be called.
mAdapter.setLoading(true);
+ mAdapter.setSuggestionsCursor(null);
mAdapter.changeCursor(null);
mAdapter.clearImageFetching();
@@ -755,21 +776,6 @@
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
searchManager.stopSearch();
}
-
- // When the orientation is changed or Home button is pressed, onStop() is called.
- // Then, we stop exporting just for safety.
- //
- // Technically, it is because the dialog displaying the current status of export is
- // closed on this method call and we cannot reliably restore the dialog in the current
- // implementation, while the thread for exporting vCard is working at that time, without
- // showing its status to users :(
- // Also, it is probably not a strong requirment for us to both
- // - enable users to press Home, slide hardware keyboard during the export
- // - and also let vCard export to keep working.
- if (mVCardExporter != null) {
- mVCardExporter.cancelExport();
- mVCardExporter = null;
- }
}
@Override
@@ -812,7 +818,7 @@
return true;
}
case R.id.menu_import_export: {
- showDialog(R.id.dialog_import_export);
+ displayImportExportDialog();
return true;
}
case R.id.menu_accounts: {
@@ -830,30 +836,9 @@
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
- case R.id.dialog_import_export: {
- return createImportExportDialog();
- }
case R.string.import_from_sim:
- case R.string.import_from_sdcard:
- case R.string.export_to_sdcard: {
- return createSelectAccountDialog(id);
- }
- case R.string.fail_reason_too_many_vcard: {
- return new AlertDialog.Builder(this)
- .setTitle(R.string.exporting_contact_failed_title)
- .setMessage(getString(R.string.exporting_contact_failed_message,
- getString(R.string.fail_reason_too_many_vcard)))
- .setPositiveButton(android.R.string.ok, null)
- .create();
- }
- case R.id.dialog_confirm_export_vcard: {
- return mVCardExporter.getExportConfirmationDialog();
- }
- case R.id.dialog_exporting_vcard: {
- return mVCardExporter.getExportingVCardDialog();
- }
- case R.id.dialog_fail_to_export_with_reason: {
- return mVCardExporter.getErrorDialogWithReason();
+ case R.string.import_from_sdcard: {
+ return AccountSelectionUtil.getSelectAccountDialog(this, id);
}
case R.id.dialog_sdcard_not_found: {
AlertDialog.Builder builder = new AlertDialog.Builder(this)
@@ -866,104 +851,11 @@
return super.onCreateDialog(id);
}
- private class AccountSelectedListener
- implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
-
- final private List<Account> mAccountList;
- final private int mResId;
-
- public AccountSelectedListener(List<Account> accountList, int resId) {
- if (accountList == null || accountList.size() == 0) {
- Log.e(TAG, "The size of Account list is 0.");
- }
- mAccountList = accountList;
- mResId = resId;
- }
-
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- switch (mResId) {
- case R.string.import_from_sim: {
- doImportFromSim(mAccountList.get(which));
- break;
- }
- case R.string.import_from_sdcard: {
- doImportFromSdCard(mAccountList.get(which));
- break;
- }
- /*case R.string.export_to_sdcard: {
- }*/
- }
- }
-
- public void onCancel(DialogInterface dialog) {
- dialog.dismiss();
- }
- }
-
- private Dialog createSelectAccountDialog(int resId) {
- final boolean isExport = (resId == R.string.export_to_sdcard);
- final boolean displayWritableOnly = !isExport;
-
- final Sources sources = Sources.getInstance(this);
- final List<Account> accountList = sources.getAccounts(displayWritableOnly);
-
- /*if (isExport) {
- accountList.add(sExportPhoneLocalAccount);
- accountList.add(sExportAllAccount);
- }*/
-
- // Assume accountList.size() > 1
-
- // Wrap our context to inflate list items using correct theme
- final Context dialogContext = new ContextThemeWrapper(
- this, android.R.style.Theme_Light);
- final LayoutInflater dialogInflater = (LayoutInflater)dialogContext
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- final ArrayAdapter<Account> accountAdapter =
- new ArrayAdapter<Account>(this, android.R.layout.simple_list_item_2, accountList) {
-
- @Override
- public View getView(int position, View convertView,
- ViewGroup parent) {
- if (convertView == null) {
- convertView = dialogInflater.inflate(
- android.R.layout.simple_list_item_2,
- parent, false);
- }
-
- // TODO: show icon along with title
- final TextView text1 =
- (TextView)convertView.findViewById(android.R.id.text1);
- final TextView text2 =
- (TextView)convertView.findViewById(android.R.id.text2);
-
- final Account account = this.getItem(position);
- final ContactsSource source =
- sources.getInflatedSource(account.type,
- ContactsSource.LEVEL_SUMMARY);
-
- text1.setText(account.name);
- text2.setText(source.getDisplayLabel(ContactsListActivity.this));
-
- return convertView;
- }
- };
-
- AccountSelectedListener listener = new AccountSelectedListener(accountList, resId);
- final AlertDialog.Builder builder =
- new AlertDialog.Builder(this)
- .setTitle(R.string.dialog_new_contact_account)
- .setSingleChoiceItems(accountAdapter, 0, listener)
- .setOnCancelListener(listener);
- return builder.create();
- }
-
/**
* Create a {@link Dialog} that allows the user to pick from a bulk import
* or bulk export task across all contacts.
*/
- private Dialog createImportExportDialog() {
+ private void displayImportExportDialog() {
// Wrap our context to inflate list items using correct theme
final Context dialogContext = new ContextThemeWrapper(this, android.R.style.Theme_Light);
final Resources res = dialogContext.getResources();
@@ -996,7 +888,8 @@
adapter.add(R.string.export_to_sdcard);
}
- final DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() {
+ final DialogInterface.OnClickListener clickListener =
+ new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
@@ -1004,12 +897,13 @@
switch (resId) {
case R.string.import_from_sim:
case R.string.import_from_sdcard: {
- handleImportExportRequest(resId);
+ handleImportRequest(resId);
break;
}
case R.string.export_to_sdcard: {
- // TODO: use handleImportExportRequest()
- doExportToSdCard();
+ Context context = ContactsListActivity.this;
+ Intent exportIntent = new Intent(context, ExportVCardActivity.class);
+ context.startActivity(exportIntent);
break;
}
default: {
@@ -1020,93 +914,27 @@
}
};
- final AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.dialog_import_export);
- builder.setNegativeButton(android.R.string.cancel, null);
- builder.setSingleChoiceItems(adapter, -1, clickListener);
- return builder.create();
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.dialog_import_export)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setSingleChoiceItems(adapter, -1, clickListener)
+ .show();
}
- private void handleImportExportRequest(int resId) {
- /*final boolean isExport = (resId == R.string.export_to_sdcard);
- if (isExport) {
- // We're sure there are at least two Account ("phone-local" and "all").
- // Go to account selection every time.
- showDialog(R.string.export_to_sdcard);
- return;
- }*/
-
- // As for import, there's three possibilities
+ private void handleImportRequest(int resId) {
+ // There's three possibilities:
// - more than one accounts -> ask the user
// - just one account -> use the account without asking the user
// - no account -> use phone-local storage without asking the user
-
final Sources sources = Sources.getInstance(this);
final List<Account> accountList = sources.getAccounts(true);
final int size = accountList.size();
- Account account;
if (size > 1) {
showDialog(resId);
return;
- } else if (size == 1) {
- account = accountList.get(0);
- } else {
- account = null;
- }
- switch (resId) {
- case R.string.import_from_sim: {
- doImportFromSim(account);
- break;
- }
- case R.string.import_from_sdcard: {
- doImportFromSdCard(account);
- break;
- }
- /*case R.string.export_to_sdcard: {
- doExportToSdCard(account);
- break;
- }*/
- }
- }
-
- private void doImportFromSim(Account account) {
- if (account != null) {
- GoogleSource.createMyContactsIfNotExist(account, this);
}
- Intent importIntent = new Intent(Intent.ACTION_VIEW);
- importIntent.setType("vnd.android.cursor.item/sim-contact");
- if (account != null) {
- importIntent.putExtra("account_name", account.name);
- importIntent.putExtra("account_type", account.type);
- }
- importIntent.setClassName("com.android.phone", "com.android.phone.SimContacts");
- startActivity(importIntent);
- }
-
- private void doImportFromSdCard(Account account) {
- if (account != null) {
- GoogleSource.createMyContactsIfNotExist(account, this);
- }
-
- Intent importIntent = new Intent(this, ImportVCardActivity.class);
- if (account != null) {
- importIntent.putExtra("account_name", account.name);
- importIntent.putExtra("account_type", account.type);
- }
- startActivity(importIntent);
- }
-
- private void doExportToSdCard() {
- mVCardExporter = new VCardExporter(this);
- mVCardExporter.startExportVCardToSdCard();
- }
-
- /**
- * Used when VCardExporter finishes its exporting.
- */
- /* package */ void removeReferenceToVCardExporter() {
- mVCardExporter = null;
+ AccountSelectionUtil.doImport(this, resId, (size == 1 ? accountList.get(0) : null));
}
@Override
@@ -1716,7 +1544,10 @@
mQueryHandler.setLoadingJoinSuggestions(false);
String[] projection = getProjectionForQuery();
- Uri uri = getUriToQuery();
+ Uri uri = getUriToQuery().buildUpon()
+ .appendQueryParameter(ContactsContract.REQUESTING_PACKAGE_PARAM_KEY,
+ getCallingPackage())
+ .build();
// Kick off the new query
switch (mMode) {
@@ -1795,7 +1626,7 @@
case MODE_JOIN_CONTACT:
mQueryHandler.setLoadingJoinSuggestions(true);
mQueryHandler.startQuery(QUERY_TOKEN, null, getJoinSuggestionsUri(null), projection,
- Contacts._ID + " != " + mQueryAggregateId, null, null);
+ null, null, null);
break;
}
}
@@ -1871,8 +1702,8 @@
null, null);
mAdapter.setSuggestionsCursor(cursor);
return resolver.query(getContactFilterUri(filter), projection,
- Contacts._ID + " != " + mQueryAggregateId, null,
- getSortOrder(projection));
+ Contacts._ID + " != " + mQueryAggregateId + " AND " + CLAUSE_ONLY_VISIBLE,
+ null, getSortOrder(projection));
}
}
throw new UnsupportedOperationException("filtering not allowed in mode " + mMode);
@@ -1929,7 +1760,7 @@
getColumnIndex(Phone.IS_SUPER_PRIMARY)) != 0) {
// Found super primary, call it.
phone = phonesCursor.
- getString(phonesCursor.getColumnIndex(Phone.NUMBER));
+ getString(phonesCursor.getColumnIndex(Phone.NUMBER));
break;
}
}
@@ -2012,7 +1843,8 @@
startQuery(QUERY_TOKEN, null, activity.getContactFilterUri(activity.mQuery),
CONTACTS_SUMMARY_PROJECTION,
- Contacts._ID + " != " + activity.mQueryAggregateId, null,
+ Contacts._ID + " != " + activity.mQueryAggregateId
+ + " AND " + CLAUSE_ONLY_VISIBLE, null,
getSortOrder(CONTACTS_SUMMARY_PROJECTION));
return;
}
@@ -2242,6 +2074,9 @@
@Override
public int getItemViewType(int position) {
+ if (position == 0 && (mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0) {
+ return IGNORE_ITEM_VIEW_TYPE;
+ }
if (getSeparatorId(position) != 0) {
// We don't want the separator view to be recycled.
return IGNORE_ITEM_VIEW_TYPE;
@@ -2256,6 +2091,17 @@
"this should only be called when the cursor is valid");
}
+ // handle the total contacts item
+ if (position == 0 && (mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0) {
+ final LayoutInflater inflater = getLayoutInflater();
+ TextView totalContacts = (TextView) inflater.inflate(R.layout.total_contacts,
+ parent, false);
+ int stringId = mDisplayOnlyPhones ? R.string.listTotalPhoneContacts
+ : R.string.listTotalAllContacts;
+ totalContacts.setText(getString(stringId, getCount()));
+ return totalContacts;
+ }
+
// Handle the separator specially
int separatorId = getSeparatorId(position);
if (separatorId != 0) {
@@ -2534,7 +2380,9 @@
// Get the split between starred and frequent items, if the mode is strequent
mFrequentSeparatorPos = ListView.INVALID_POSITION;
- if (cursor != null && cursor.getCount() > 0 && mMode == MODE_STREQUENT) {
+ int cursorCount = 0;
+ if (cursor != null && (cursorCount = cursor.getCount()) > 0
+ && mMode == MODE_STREQUENT) {
cursor.move(-1);
for (int i = 0; cursor.moveToNext(); i++) {
int starred = cursor.getInt(SUMMARY_STARRED_COLUMN_INDEX);
@@ -2549,7 +2397,6 @@
}
super.changeCursor(cursor);
-
// Update the indexer for the fast scroll widget
updateIndexer(cursor);
}
@@ -2661,6 +2508,12 @@
@Override
public boolean isEnabled(int position) {
+ if ((mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0) {
+ if (position == 0) {
+ return false;
+ }
+ position--;
+ }
if (mSuggestionsCursorCount > 0) {
return position != 0 && position != mSuggestionsCursorCount + 1;
}
@@ -2683,6 +2536,9 @@
}
private int getRealPosition(int pos) {
+ if ((mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0) {
+ pos--;
+ }
if (mSuggestionsCursorCount != 0) {
// When showing suggestions, we have 2 additional list items: the "Suggestions"
// and "All contacts" separators.
diff --git a/src/com/android/contacts/ExportVCardActivity.java b/src/com/android/contacts/ExportVCardActivity.java
new file mode 100644
index 0000000..08f43c1
--- /dev/null
+++ b/src/com/android/contacts/ExportVCardActivity.java
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.contacts;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.PowerManager;
+import android.pim.vcard.VCardComposer;
+import android.provider.ContactsContract.Contacts;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.util.HashSet;
+import java.util.Set;
+
+public class ExportVCardActivity extends Activity {
+ private static final String LOG_TAG = "ExportVCardActivity";
+
+ // If true, VCardExporter is able to emits files longer than 8.3 format.
+ private static final boolean ALLOW_LONG_FILE_NAME = false;
+ private String mTargetDirectory;
+ private String mFileNamePrefix;
+ private String mFileNameSuffix;
+ private int mFileIndexMinimum;
+ private int mFileIndexMaximum;
+ private String mFileNameExtension;
+ private String mVCardTypeStr;
+ private Set<String> mExtensionsToConsider;
+
+ private ProgressDialog mProgressDialog;
+
+ private Handler mHandler = new Handler();
+
+ // Used temporaly when asking users to confirm the file name
+ private String mTargetFileName;
+
+ // String for storing error reason temporaly.
+ private String mErrorReason;
+
+ private ActualExportThread mActualExportThread;
+
+ private class CancelListener
+ implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ public void onCancel(DialogInterface dialog) {
+ finish();
+ }
+ }
+
+ private CancelListener mCancelListener = new CancelListener();
+
+ private class ErrorReasonDisplayer implements Runnable {
+ private final int mResId;
+ public ErrorReasonDisplayer(int resId) {
+ mResId = resId;
+ }
+ public ErrorReasonDisplayer(String errorReason) {
+ mResId = R.id.dialog_fail_to_export_with_reason;
+ mErrorReason = errorReason;
+ }
+ public void run() {
+ // Show the Dialog only when the parent Activity is still alive.
+ if (!ExportVCardActivity.this.isFinishing()) {
+ showDialog(mResId);
+ }
+ }
+ }
+
+ private class ExportConfirmationListener implements DialogInterface.OnClickListener {
+ private final String mFileName;
+
+ public ExportConfirmationListener(String fileName) {
+ mFileName = fileName;
+ }
+
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ mActualExportThread = new ActualExportThread(mFileName);
+ String title = getString(R.string.exporting_contact_list_title);
+ String message = getString(R.string.exporting_contact_list_message, mFileName);
+ mProgressDialog = new ProgressDialog(ExportVCardActivity.this);
+ mProgressDialog.setTitle(title);
+ mProgressDialog.setMessage(message);
+ mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ mProgressDialog.setOnCancelListener(mActualExportThread);
+ mProgressDialog.show();
+ mActualExportThread.start();
+ }
+ }
+ }
+
+ private class ActualExportThread extends Thread
+ implements DialogInterface.OnCancelListener {
+ private PowerManager.WakeLock mWakeLock;
+ private String mFileName;
+ private boolean mCanceled = false;
+
+ public ActualExportThread(String fileName) {
+ mFileName = fileName;
+ PowerManager powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
+ mWakeLock = powerManager.newWakeLock(
+ PowerManager.SCREEN_DIM_WAKE_LOCK |
+ PowerManager.ON_AFTER_RELEASE, LOG_TAG);
+ }
+
+ @Override
+ public void run() {
+ boolean shouldCallFinish = true;
+ mWakeLock.acquire();
+ VCardComposer composer = null;
+ try {
+ OutputStream outputStream = null;
+ try {
+ outputStream = new FileOutputStream(mFileName);
+ } catch (FileNotFoundException e) {
+ final String errorReason =
+ getString(R.string.fail_reason_could_not_open_file,
+ mFileName, e.getMessage());
+ shouldCallFinish = false;
+ mHandler.post(new ErrorReasonDisplayer(errorReason));
+ return;
+ }
+
+ composer = new VCardComposer(ExportVCardActivity.this, mVCardTypeStr, true);
+ // composer = new VCardComposer(ExportVCardActivity,
+ // VCardConfig.VCARD_TYPE_V30_JAPANESE_UTF8, true);
+ composer.addHandler(composer.new HandlerForOutputStream(outputStream));
+
+ if (!composer.init()) {
+ final String errorReason = composer.getErrorReason();
+ Log.e(LOG_TAG, "initialization of vCard composer failed: " + errorReason);
+ final String translatedErrorReason =
+ translateComposerError(errorReason);
+ mHandler.post(new ErrorReasonDisplayer(
+ getString(R.string.fail_reason_could_not_initialize_exporter,
+ translatedErrorReason)));
+ shouldCallFinish = false;
+ return;
+ }
+
+ int size = composer.getCount();
+
+ if (size == 0) {
+ mHandler.post(new ErrorReasonDisplayer(
+ getString(R.string.fail_reason_no_exportable_contact)));
+ shouldCallFinish = false;
+ return;
+ }
+
+ mProgressDialog.setProgressNumberFormat(
+ getString(R.string.exporting_contact_list_progress));
+ mProgressDialog.setMax(size);
+ mProgressDialog.setProgress(0);
+
+ while (!composer.isAfterLast()) {
+ if (mCanceled) {
+ return;
+ }
+ if (!composer.createOneEntry()) {
+ final String errorReason = composer.getErrorReason();
+ Log.e(LOG_TAG, "Failed to read a contact: " + errorReason);
+ final String translatedErrorReason =
+ translateComposerError(errorReason);
+ mHandler.post(new ErrorReasonDisplayer(
+ getString(R.string.fail_reason_error_occurred_during_export,
+ translatedErrorReason)));
+ shouldCallFinish = false;
+ return;
+ }
+ mProgressDialog.incrementProgressBy(1);
+ }
+ } finally {
+ if (composer != null) {
+ composer.terminate();
+ }
+ mWakeLock.release();
+ mProgressDialog.dismiss();
+ if (shouldCallFinish && !isFinishing()) {
+ finish();
+ }
+ }
+ }
+
+ @Override
+ public void finalize() {
+ if (mWakeLock != null && mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
+ }
+
+ public void cancel() {
+ mCanceled = true;
+ }
+
+ public void onCancel(DialogInterface dialog) {
+ cancel();
+ }
+ }
+
+ private String translateComposerError(String errorMessage) {
+ Resources resources = getResources();
+ if (VCardComposer.FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO.equals(errorMessage)) {
+ return resources.getString(R.string.composer_failed_to_get_database_infomation);
+ } else if (VCardComposer.FAILURE_REASON_NO_ENTRY.equals(errorMessage)) {
+ return resources.getString(R.string.composer_has_no_exportable_contact);
+ } else if (VCardComposer.FAILURE_REASON_NOT_INITIALIZED.equals(errorMessage)) {
+ return resources.getString(R.string.composer_not_initialized);
+ } else {
+ return errorMessage;
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+
+ mTargetDirectory = getString(R.string.config_export_dir);
+ mFileNamePrefix = getString(R.string.config_export_file_prefix);
+ mFileNameSuffix = getString(R.string.config_export_file_suffix);
+ mFileNameExtension = getString(R.string.config_export_file_extension);
+ mVCardTypeStr = getString(R.string.config_export_vcard_type);
+
+ mExtensionsToConsider = new HashSet<String>();
+ mExtensionsToConsider.add(mFileNameExtension);
+
+ final String additionalExtensions =
+ getString(R.string.config_export_extensions_to_consider);
+ if (!TextUtils.isEmpty(additionalExtensions)) {
+ for (String extension : additionalExtensions.split(",")) {
+ String trimed = extension.trim();
+ if (trimed.length() > 0) {
+ mExtensionsToConsider.add(trimed);
+ }
+ }
+ }
+
+ final Resources resources = getResources();
+ mFileIndexMinimum = resources.getInteger(R.integer.config_export_file_min_index);
+ mFileIndexMaximum = resources.getInteger(R.integer.config_export_file_max_index);
+
+ startExportVCardToSdCard();
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ switch (id) {
+ case R.id.dialog_export_confirmation: {
+ return getExportConfirmationDialog();
+ }
+ case R.string.fail_reason_too_many_vcard: {
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.exporting_contact_failed_title)
+ .setMessage(getString(R.string.exporting_contact_failed_message,
+ getString(R.string.fail_reason_too_many_vcard)))
+ .setPositiveButton(android.R.string.ok, mCancelListener)
+ .create();
+ }
+ case R.id.dialog_fail_to_export_with_reason: {
+ return getErrorDialogWithReason();
+ }
+ case R.id.dialog_sdcard_not_found: {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this)
+ .setTitle(R.string.no_sdcard_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(R.string.no_sdcard_message)
+ .setPositiveButton(android.R.string.ok, mCancelListener);
+ }
+ }
+ return super.onCreateDialog(id);
+ }
+
+ @Override
+ protected void onPrepareDialog(int id, Dialog dialog) {
+ if (id == R.id.dialog_fail_to_export_with_reason) {
+ ((AlertDialog)dialog).setMessage(getErrorReason());
+ } else if (id == R.id.dialog_export_confirmation) {
+ ((AlertDialog)dialog).setMessage(
+ getString(R.string.confirm_export_message, mTargetFileName));
+ } else {
+ super.onPrepareDialog(id, dialog);
+ }
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ if (mActualExportThread != null) {
+ // The Activity is no longer visible. Stop the thread.
+ mActualExportThread.cancel();
+ mActualExportThread = null;
+ }
+
+ if (!isFinishing()) {
+ finish();
+ }
+ }
+
+ /**
+ * Tries to start exporting VCard. If there's no SDCard available,
+ * an error dialog is shown.
+ */
+ public void startExportVCardToSdCard() {
+ File targetDirectory = new File(mTargetDirectory);
+
+ if (!(targetDirectory.exists() &&
+ targetDirectory.isDirectory() &&
+ targetDirectory.canRead()) &&
+ !targetDirectory.mkdirs()) {
+ showDialog(R.id.dialog_sdcard_not_found);
+ } else {
+ mTargetFileName = getAppropriateFileName(mTargetDirectory);
+ if (TextUtils.isEmpty(mTargetFileName)) {
+ mTargetFileName = null;
+ // finish() is called via the error dialog. Do not call the method here.
+ return;
+ }
+
+ showDialog(R.id.dialog_export_confirmation);
+ }
+ }
+
+ /**
+ * Tries to get an appropriate filename. Returns null if it fails.
+ */
+ private String getAppropriateFileName(final String destDirectory) {
+ int fileNumberStringLength = 0;
+ {
+ // Calling Math.Log10() is costly.
+ int tmp;
+ for (fileNumberStringLength = 0, tmp = mFileIndexMaximum; tmp > 0;
+ fileNumberStringLength++, tmp /= 10) {
+ }
+ }
+ String bodyFormat = "%s%0" + fileNumberStringLength + "d%s";
+
+ if (!ALLOW_LONG_FILE_NAME) {
+ String possibleBody = String.format(bodyFormat,mFileNamePrefix, 1, mFileNameSuffix);
+ if (possibleBody.length() > 8 || mFileNameExtension.length() > 3) {
+ Log.e(LOG_TAG, "This code does not allow any long file name.");
+ mErrorReason = getString(R.string.fail_reason_too_long_filename,
+ String.format("%s.%s", possibleBody, mFileNameExtension));
+ showDialog(R.id.dialog_fail_to_export_with_reason);
+ // finish() is called via the error dialog. Do not call the method here.
+ return null;
+ }
+ }
+
+ // Note that this logic assumes that the target directory is case insensitive.
+ // As of 2009-07-16, it is true since the external storage is only sdcard, and
+ // it is formated as FAT/VFAT.
+ // TODO: fix this.
+ for (int i = mFileIndexMinimum; i <= mFileIndexMaximum; i++) {
+ boolean numberIsAvailable = true;
+ // SD Association's specification seems to require this feature, though we cannot
+ // have the specification since it is proprietary...
+ String body = null;
+ for (String possibleExtension : mExtensionsToConsider) {
+ body = String.format(bodyFormat, mFileNamePrefix, i, mFileNameSuffix);
+ File file = new File(String.format("%s/%s.%s",
+ destDirectory, body, possibleExtension));
+ if (file.exists()) {
+ numberIsAvailable = false;
+ break;
+ }
+ }
+ if (numberIsAvailable) {
+ return String.format("%s/%s.%s", destDirectory, body, mFileNameExtension);
+ }
+ }
+ showDialog(R.string.fail_reason_too_many_vcard);
+ return null;
+ }
+
+ public Dialog getExportConfirmationDialog() {
+ if (TextUtils.isEmpty(mTargetFileName)) {
+ Log.e(LOG_TAG, "Target file name is empty, which must not be!");
+ // This situation is not acceptable (probably a bug!), but we don't have no reason to
+ // show...
+ mErrorReason = null;
+ return getErrorDialogWithReason();
+ }
+
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.confirm_export_title)
+ .setMessage(getString(R.string.confirm_export_message, mTargetFileName))
+ .setPositiveButton(android.R.string.ok,
+ new ExportConfirmationListener(mTargetFileName))
+ .setNegativeButton(android.R.string.cancel, mCancelListener)
+ .setOnCancelListener(mCancelListener)
+ .create();
+ }
+
+ public Dialog getErrorDialogWithReason() {
+ if (mErrorReason == null) {
+ Log.e(LOG_TAG, "Error reason must have been set.");
+ mErrorReason = getString(R.string.fail_reason_unknown);
+ }
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.exporting_contact_failed_title)
+ .setMessage(getString(R.string.exporting_contact_failed_message, mErrorReason))
+ .setPositiveButton(android.R.string.ok, mCancelListener)
+ .setOnCancelListener(mCancelListener)
+ .create();
+ }
+
+ public void cancelExport() {
+ if (mActualExportThread != null) {
+ mActualExportThread.cancel();
+ mActualExportThread = null;
+ }
+ }
+
+ public String getErrorReason() {
+ return mErrorReason;
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/ImportVCardActivity.java b/src/com/android/contacts/ImportVCardActivity.java
index e77a3e8..64b5727 100644
--- a/src/com/android/contacts/ImportVCardActivity.java
+++ b/src/com/android/contacts/ImportVCardActivity.java
@@ -531,22 +531,14 @@
mProgressDialogForScanVCard = null;
if (mGotIOException) {
- mHandler.post(new Runnable() {
- public void run() {
- showDialog(R.id.dialog_io_exception);
- }
- });
+ mHandler.post(new DialogDisplayer(R.id.dialog_io_exception));
} else if (mCanceled) {
finish();
} else {
int size = mAllVCardFileList.size();
final Context context = ImportVCardActivity.this;
if (size == 0) {
- mHandler.post(new Runnable() {
- public void run() {
- showDialog(R.id.dialog_vcard_not_found);
- }
- });
+ mHandler.post(new DialogDisplayer(R.id.dialog_vcard_not_found));
} else {
startVCardSelectAndImport();
}
diff --git a/src/com/android/contacts/PhoneDisambigDialog.java b/src/com/android/contacts/PhoneDisambigDialog.java
index 58d3721..b727c77 100644
--- a/src/com/android/contacts/PhoneDisambigDialog.java
+++ b/src/com/android/contacts/PhoneDisambigDialog.java
@@ -17,8 +17,9 @@
package com.android.contacts;
import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
+import java.util.List;
+
+import com.android.contacts.Collapser.Collapsible;
import android.app.AlertDialog;
import android.content.ContentUris;
@@ -28,12 +29,13 @@
import android.database.Cursor;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.telephony.PhoneNumberUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
-import android.widget.SimpleCursorAdapter;
+import android.widget.ListAdapter;
/**
* Class used for displaying a dialog with a list of phone numbers of which
@@ -47,6 +49,8 @@
private AlertDialog mDialog;
private boolean mSendSms;
private Cursor mPhonesCursor;
+ private ListAdapter mPhonesAdapter;
+ private ArrayList<PhoneItem> mPhoneItemList;
public PhoneDisambigDialog(Context context, Cursor phonesCursor) {
this(context, phonesCursor, false /*make call*/);
@@ -57,6 +61,11 @@
mSendSms = sendSms;
mPhonesCursor = phonesCursor;
+ mPhoneItemList = makePhoneItemsList(phonesCursor);
+ Collapser.collapseList(mPhoneItemList);
+
+ mPhonesAdapter = new PhonesAdapter(mContext, mPhoneItemList);
+
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
View setPrimaryView = inflater.
@@ -66,9 +75,10 @@
// Need to show disambig dialogue.
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext).
- setCursor(mPhonesCursor, this, Phone.NUMBER).
- setTitle(sendSms ? R.string.sms_disambig_title : R.string.call_disambig_title).
- setView(setPrimaryView);
+ setAdapter(mPhonesAdapter, this).
+ setTitle(sendSms ?
+ R.string.sms_disambig_title : R.string.call_disambig_title).
+ setView(setPrimaryView);
mDialog = dialogBuilder.create();
}
@@ -77,18 +87,25 @@
* Show the dialog.
*/
public void show() {
+ if (mPhoneItemList.size() == 1) {
+ // If there is only one after collapse, just select it, and close;
+ onClick(mDialog, 0);
+ return;
+ }
mDialog.show();
}
public void onClick(DialogInterface dialog, int which) {
- if (mPhonesCursor.moveToPosition(which)) {
- long id = mPhonesCursor.getLong(mPhonesCursor.getColumnIndex(Data._ID));
- String phone = mPhonesCursor.getString(mPhonesCursor.getColumnIndex(Phone.NUMBER));
+ if (mPhoneItemList.size() > which && which >= 0) {
+ PhoneItem phoneItem = mPhoneItemList.get(which);
+ long id = phoneItem.id;
+ String phone = phoneItem.phoneNumber;
+
if (mMakePrimary) {
ContentValues values = new ContentValues(1);
values.put(Data.IS_SUPER_PRIMARY, 1);
- mContext.getContentResolver().update(ContentUris.withAppendedId(Data.CONTENT_URI, id),
- values, null, null);
+ mContext.getContentResolver().update(ContentUris.
+ withAppendedId(Data.CONTENT_URI, id), values, null, null);
}
if (mSendSms) {
@@ -108,4 +125,56 @@
public void onDismiss(DialogInterface dialog) {
mPhonesCursor.close();
}
+
+ private static class PhonesAdapter extends ArrayAdapter<PhoneItem> {
+
+ public PhonesAdapter(Context context, List<PhoneItem> objects) {
+ super(context, android.R.layout.simple_dropdown_item_1line,
+ android.R.id.text1, objects);
+ }
+ }
+
+ private class PhoneItem implements Collapsible<PhoneItem> {
+
+ String phoneNumber;
+ long id;
+
+ public PhoneItem(String newPhoneNumber, long newId) {
+ phoneNumber = newPhoneNumber;
+ id = newId;
+ }
+
+ public boolean collapseWith(PhoneItem phoneItem) {
+ if (!shouldCollapseWith(phoneItem)) {
+ return false;
+ }
+ // Just keep the number and id we already have.
+ return true;
+ }
+
+ public boolean shouldCollapseWith(PhoneItem phoneItem) {
+ if (PhoneNumberUtils.compare(PhoneDisambigDialog.this.mContext,
+ phoneNumber, phoneItem.phoneNumber)) {
+ return true;
+ }
+ return false;
+ }
+
+ public String toString() {
+ return phoneNumber;
+ }
+ }
+
+ private ArrayList<PhoneItem> makePhoneItemsList(Cursor phonesCursor) {
+ ArrayList<PhoneItem> phoneList = new ArrayList<PhoneItem>();
+
+ phonesCursor.moveToPosition(-1);
+ while (phonesCursor.moveToNext()) {
+ long id = phonesCursor.getLong(phonesCursor.getColumnIndex(Data._ID));
+ String phone = phonesCursor.getString(phonesCursor.getColumnIndex(Phone.NUMBER));
+ phoneList.add(new PhoneItem(phone, id));
+ }
+
+ return phoneList;
+ }
}
diff --git a/src/com/android/contacts/RecentCallsListActivity.java b/src/com/android/contacts/RecentCallsListActivity.java
index decce7b..d892def 100644
--- a/src/com/android/contacts/RecentCallsListActivity.java
+++ b/src/com/android/contacts/RecentCallsListActivity.java
@@ -453,7 +453,11 @@
// Format the cached call_log phone number
formattedNumber = formatPhoneNumber(number);
}
- // Set the text lines
+ // Set the text lines and call icon.
+ // Assumes the call back feature is on most of the
+ // time. For private and unknown numbers: hide it.
+ views.callView.setVisibility(View.VISIBLE);
+
if (!TextUtils.isEmpty(name)) {
views.line1View.setText(name);
views.labelView.setVisibility(View.VISIBLE);
@@ -470,8 +474,10 @@
} else {
if (number.equals(CallerInfo.UNKNOWN_NUMBER)) {
number = getString(R.string.unknown);
+ views.callView.setVisibility(View.INVISIBLE);
} else if (number.equals(CallerInfo.PRIVATE_NUMBER)) {
number = getString(R.string.private_num);
+ views.callView.setVisibility(View.INVISIBLE);
} else if (number.equals(CallerInfo.PAYPHONE_NUMBER)) {
number = getString(R.string.payphone);
} else if (number.equals(mVoiceMailNumber)) {
diff --git a/src/com/android/contacts/ScrollingTabWidget.java b/src/com/android/contacts/ScrollingTabWidget.java
index 6974a6e..b45abe4 100644
--- a/src/com/android/contacts/ScrollingTabWidget.java
+++ b/src/com/android/contacts/ScrollingTabWidget.java
@@ -18,12 +18,7 @@
import android.content.Context;
import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
import android.util.AttributeSet;
-import android.util.Log;
-import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -32,7 +27,6 @@
import android.view.View.OnFocusChangeListener;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
-import android.widget.LinearLayout;
import android.widget.RelativeLayout;
/*
@@ -82,6 +76,7 @@
mTabsScrollWrapper = (HorizontalScrollView) mInflater.inflate(
R.layout.tab_layout, this, false);
mTabsView = (TabStripView) mTabsScrollWrapper.findViewById(android.R.id.tabs);
+ View accountNameView = mInflater.inflate(R.layout.tab_account_name, this, false);
mLeftArrowView.setVisibility(View.INVISIBLE);
mRightArrowView.setVisibility(View.INVISIBLE);
@@ -89,6 +84,7 @@
addView(mTabsScrollWrapper);
addView(mLeftArrowView);
addView(mRightArrowView);
+ addView(accountNameView);
}
@Override
diff --git a/src/com/android/contacts/TwelveKeyDialer.java b/src/com/android/contacts/TwelveKeyDialer.java
index d07d785..58ba9d8 100644
--- a/src/com/android/contacts/TwelveKeyDialer.java
+++ b/src/com/android/contacts/TwelveKeyDialer.java
@@ -1028,6 +1028,8 @@
digits.replace(selectionStart, selectionStart, newDigits);
} else {
digits.replace(selectionStart, selectionEnd, newDigits);
+ // Unselect: back to a regular cursor, just pass the character inserted.
+ mDigits.setSelection(selectionStart + 1);
}
} else {
int len = mDigits.length();
diff --git a/src/com/android/contacts/VCardExporter.java b/src/com/android/contacts/VCardExporter.java
deleted file mode 100644
index 5f13e99..0000000
--- a/src/com/android/contacts/VCardExporter.java
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.contacts;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.res.Resources;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.pim.vcard.VCardComposer;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.OutputStream;
-import java.util.HashSet;
-import java.util.Set;
-
-public class VCardExporter {
- private static final String LOG_TAG = "VCardExporter";
-
- // If true, VCardExporter is able to emits files longer than 8.3 format.
- private static final boolean ALLOW_LONG_FILE_NAME = false;
- private final String mTargetDirectory;
- private final String mFileNamePrefix;
- private final String mFileNameSuffix;
- private final int mFileIndexMinimum;
- private final int mFileIndexMaximum;
- private final String mFileNameExtension;
- private final String mVCardTypeStr;
- private final Set<String> mExtensionsToConsider;
-
- private ContactsListActivity mParentActivity;
- private ProgressDialog mProgressDialog;
-
- // Used temporaly when asking users to confirm the file name
- private String mTargetFileName;
-
- // String for storing error reason temporaly.
- private String mErrorReason;
-
- private ActualExportThread mActualExportThread;
-
- private class ConfirmListener implements DialogInterface.OnClickListener {
- private String mFileName;
-
- public ConfirmListener(String fileName) {
- mFileName = fileName;
- }
-
- public void onClick(DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON_POSITIVE) {
- mActualExportThread = new ActualExportThread(mFileName);
- String title = getString(R.string.exporting_contact_list_title);
- String message = getString(R.string.exporting_contact_list_message, mFileName);
- mProgressDialog = new ProgressDialog(mParentActivity);
- mProgressDialog.setTitle(title);
- mProgressDialog.setMessage(message);
- mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
- mProgressDialog.setOnCancelListener(mActualExportThread);
- mParentActivity.showDialog(R.id.dialog_exporting_vcard);
- mActualExportThread.start();
- }
- }
- }
-
- private class ActualExportThread extends Thread
- implements DialogInterface.OnCancelListener {
- private PowerManager.WakeLock mWakeLock;
- private String mFileName;
- private boolean mCanceled = false;
-
- public ActualExportThread(String fileName) {
- mFileName = fileName;
- PowerManager powerManager = (PowerManager)mParentActivity.getSystemService(
- Context.POWER_SERVICE);
- mWakeLock = powerManager.newWakeLock(
- PowerManager.SCREEN_DIM_WAKE_LOCK |
- PowerManager.ON_AFTER_RELEASE, LOG_TAG);
- }
-
- @Override
- public void run() {
- mWakeLock.acquire();
- VCardComposer composer = null;
- try {
- OutputStream outputStream = null;
- try {
- outputStream = new FileOutputStream(mFileName);
- } catch (FileNotFoundException e) {
- mErrorReason = getString(R.string.fail_reason_could_not_open_file,
- mFileName, e.getMessage());
- mParentActivity.showDialog(R.id.dialog_fail_to_export_with_reason);
- return;
- }
-
- composer = new VCardComposer(mParentActivity, mVCardTypeStr, true);
- // composer = new VCardComposer(mParentContext,
- // VCardConfig.VCARD_TYPE_V30_JAPANESE_UTF8, true);
- composer.addHandler(composer.new HandlerForOutputStream(outputStream));
-
- if (!composer.init()) {
- mErrorReason = getString(R.string.fail_reason_could_not_initialize_exporter,
- composer.getErrorReason());
- mParentActivity.showDialog(R.id.dialog_fail_to_export_with_reason);
- return;
- }
-
- int size = composer.getCount();
-
- mProgressDialog.setProgressNumberFormat(
- getString(R.string.exporting_contact_list_progress));
- mProgressDialog.setMax(size);
- mProgressDialog.setProgress(0);
-
- while (!composer.isAfterLast()) {
- if (mCanceled) {
- return;
- }
- if (!composer.createOneEntry()) {
- Log.e(LOG_TAG, "Failed to read a contact.");
- mErrorReason = getString(R.string.fail_reason_error_occurred_during_export,
- composer.getErrorReason());
- mParentActivity.showDialog(R.id.dialog_fail_to_export_with_reason);
- return;
- }
- mProgressDialog.incrementProgressBy(1);
- }
- } finally {
- if (composer != null) {
- composer.terminate();
- }
- mWakeLock.release();
- mProgressDialog.dismiss();
- mParentActivity.removeReferenceToVCardExporter();
- }
- }
-
- @Override
- public void finalize() {
- if (mWakeLock != null && mWakeLock.isHeld()) {
- mWakeLock.release();
- }
- }
-
- public void cancel() {
- mCanceled = true;
- }
-
- public void onCancel(DialogInterface dialog) {
- cancel();
- }
- }
-
- /**
- * @param parentActivity must not be null
- */
- public VCardExporter(ContactsListActivity parentActivity) {
- mParentActivity = parentActivity;
- mTargetDirectory = getString(R.string.config_export_dir);
- mFileNamePrefix = getString(R.string.config_export_file_prefix);
- mFileNameSuffix = getString(R.string.config_export_file_suffix);
- mFileNameExtension = getString(R.string.config_export_file_extension);
- mVCardTypeStr = getString(R.string.config_export_vcard_type);
-
- mExtensionsToConsider = new HashSet<String>();
- mExtensionsToConsider.add(mFileNameExtension);
-
- final String additionalExtensions =
- getString(R.string.config_export_extensions_to_consider);
- if (!TextUtils.isEmpty(additionalExtensions)) {
- for (String extension : additionalExtensions.split(",")) {
- String trimed = extension.trim();
- if (trimed.length() > 0) {
- mExtensionsToConsider.add(trimed);
- }
- }
- }
-
- Resources resources = parentActivity.getResources();
- mFileIndexMinimum = resources.getInteger(R.integer.config_export_file_min_index);
- mFileIndexMaximum = resources.getInteger(R.integer.config_export_file_max_index);
- }
-
- /**
- * Tries to start exporting VCard. If there's no SDCard available,
- * an error dialog is shown.
- */
- public void startExportVCardToSdCard() {
- File targetDirectory = new File(mTargetDirectory);
-
- if (!(targetDirectory.exists() &&
- targetDirectory.isDirectory() &&
- targetDirectory.canRead()) &&
- !targetDirectory.mkdirs()) {
- mParentActivity.showDialog(R.id.dialog_sdcard_not_found);
- } else {
- mTargetFileName = getAppropriateFileName(mTargetDirectory);
- if (TextUtils.isEmpty(mTargetFileName)) {
- mTargetFileName = null;
- return;
- }
-
- mParentActivity.showDialog(R.id.dialog_confirm_export_vcard);
- }
- }
-
- /**
- * Tries to get an appropriate filename. Returns null if it fails.
- */
- private String getAppropriateFileName(final String destDirectory) {
- int fileNumberStringLength = 0;
- {
- // Calling Math.Log10() is costly.
- int tmp;
- for (fileNumberStringLength = 0, tmp = mFileIndexMaximum; tmp > 0;
- fileNumberStringLength++, tmp /= 10) {
- }
- }
- String bodyFormat = "%s%0" + fileNumberStringLength + "d%s";
-
- if (!ALLOW_LONG_FILE_NAME) {
- String possibleBody = String.format(bodyFormat,mFileNamePrefix, 1, mFileNameSuffix);
- if (possibleBody.length() > 8 || mFileNameExtension.length() > 3) {
- Log.e(LOG_TAG, "This code does not allow any long file name.");
- mErrorReason = getString(R.string.fail_reason_too_long_filename,
- String.format("%s.%s", possibleBody, mFileNameExtension));
- mParentActivity.showDialog(R.id.dialog_fail_to_export_with_reason);
- return null;
- }
- }
-
- // Note that this logic assumes that the target directory is case insensitive.
- // As of 2009-07-16, it is true since the external storage is only sdcard, and
- // it is formated as FAT/VFAT.
- // TODO: fix this.
- for (int i = mFileIndexMinimum; i <= mFileIndexMaximum; i++) {
- boolean numberIsAvailable = true;
- // SD Association's specification seems to require this feature, though we cannot
- // have the specification since it is proprietary...
- String body = null;
- for (String possibleExtension : mExtensionsToConsider) {
- body = String.format(bodyFormat, mFileNamePrefix, i, mFileNameSuffix);
- File file = new File(String.format("%s/%s.%s",
- destDirectory, body, possibleExtension));
- if (file.exists()) {
- numberIsAvailable = false;
- break;
- }
- }
- if (numberIsAvailable) {
- return String.format("%s/%s.%s", destDirectory, body, mFileNameExtension);
- }
- }
- mParentActivity.showDialog(R.string.fail_reason_too_many_vcard);
- return null;
- }
-
- public Dialog getExportConfirmationDialog() {
- if (TextUtils.isEmpty(mTargetFileName)) {
- Log.e(LOG_TAG, "Target file name is empty, which must not be!");
- // This situation is not acceptable (probably a bug!), but we don't have no reason to
- // show...
- mErrorReason = null;
- return getErrorDialogWithReason();
- }
-
- return new AlertDialog.Builder(mParentActivity)
- .setTitle(R.string.confirm_export_title)
- .setMessage(getString(R.string.confirm_export_message, mTargetFileName))
- .setPositiveButton(android.R.string.ok, new ConfirmListener(mTargetFileName))
- .setNegativeButton(android.R.string.cancel, null)
- .create();
- }
-
- public Dialog getExportingVCardDialog() {
- return mProgressDialog;
- }
-
- public Dialog getErrorDialogWithReason() {
- if (mErrorReason == null) {
- Log.e(LOG_TAG, "Error reason must have been set.");
- mErrorReason = getString(R.string.fail_reason_unknown);
- }
- return new AlertDialog.Builder(mParentActivity)
- .setTitle(R.string.exporting_contact_failed_title)
- .setMessage(getString(R.string.exporting_contact_failed_message, mErrorReason))
- .setPositiveButton(android.R.string.ok, null)
- .create();
- }
-
- public void cancelExport() {
- if (mActualExportThread != null) {
- mActualExportThread.cancel();
- mActualExportThread = null;
- }
- }
-
- private String getString(int resId, Object... formatArgs) {
- return mParentActivity.getString(resId, formatArgs);
- }
-
- private String getString(int resId) {
- return mParentActivity.getString(resId);
- }
-}
\ No newline at end of file
diff --git a/src/com/android/contacts/ViewContactActivity.java b/src/com/android/contacts/ViewContactActivity.java
index 1b2ee23..8172423 100644
--- a/src/com/android/contacts/ViewContactActivity.java
+++ b/src/com/android/contacts/ViewContactActivity.java
@@ -74,13 +74,11 @@
import android.view.Window;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
import android.view.animation.TranslateAnimation;
import android.view.animation.Animation.AnimationListener;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.ImageView;
-import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
@@ -103,6 +101,7 @@
private static final int DIALOG_CONFIRM_DELETE = 1;
private static final int REQUEST_JOIN_CONTACT = 1;
+ private static final int REQUEST_EDIT_CONTACT = 2;
public static final int MENU_ITEM_MAKE_DEFAULT = 3;
@@ -136,6 +135,7 @@
protected ScrollingTabWidget mTabWidget;
protected ContactHeaderWidget mContactHeaderWidget;
protected View mBelowHeader;
+ protected TextView mAccountName;
protected View mBufferView;
private NotifyingAsyncQueryHandler mHandler;
@@ -151,7 +151,9 @@
protected static final int TAB_ACCOUNT_NAME_COLUMN_INDEX = 1;
protected static final int TAB_ACCOUNT_TYPE_COLUMN_INDEX = 2;
- protected static final String SELECTED_RAW_CONTACT_ID_KEY = "selectedRawContact";
+ private static final String SAVED_STATE_SELECTED_RAW_CONTACT_ID_KEY = "selectedRawContactKey";
+ private static final String SAVED_STATE_TABS_VISIBLE_KEY = "tabsVisibleKey";
+
protected Long mSelectedRawContactId = null;
private static final int TOKEN_QUERY = 0;
@@ -213,6 +215,7 @@
mTabWidget.setTabSelectionListener(this);
mTabWidget.setVisibility(View.GONE);
mTabsVisible = false;
+ mAccountName = (TextView) mTabWidget.findViewById(R.id.account_name);
mBelowHeader = findViewById(R.id.below_header);
@@ -247,9 +250,27 @@
}
@Override
+ protected void onRestoreInstanceState(Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ long restoredRawContactId = savedInstanceState.getLong(
+ SAVED_STATE_SELECTED_RAW_CONTACT_ID_KEY, -1);
+ mSelectedRawContactId = restoredRawContactId != -1 ? restoredRawContactId : null;
+ mTabsVisible = savedInstanceState.getBoolean(SAVED_STATE_TABS_VISIBLE_KEY);
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ if (mSelectedRawContactId != null) {
+ outState.putLong(SAVED_STATE_SELECTED_RAW_CONTACT_ID_KEY, mSelectedRawContactId);
+
+ }
+ outState.putBoolean(SAVED_STATE_TABS_VISIBLE_KEY, mTabsVisible);
+ }
+
+ @Override
protected void onResume() {
super.onResume();
- showTabs(false, false /*no animation*/);
startEntityQuery();
}
@@ -371,80 +392,71 @@
return -1;
}
- protected void showTabs(boolean show, boolean animate) {
+ protected void showTabs(boolean show) {
if (mTabsVisible == show) {
return;
}
- float tabHeight = getResources().getDimension(R.dimen.tab_height);
+ final Resources resources = getResources();
+ final float tabHeight = resources.getDimension(R.dimen.tab_height)
+ + resources.getDimension(R.dimen.account_name_height);
if (show) {
- if (animate) {
- TranslateAnimation showAnimation = new TranslateAnimation(
- Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 0,
- Animation.ABSOLUTE, -tabHeight, Animation.ABSOLUTE, 0);
- showAnimation.setDuration(getResources().getInteger(
- android.R.integer.config_longAnimTime));
+ TranslateAnimation showAnimation = new TranslateAnimation(
+ Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 0,
+ Animation.ABSOLUTE, -tabHeight, Animation.ABSOLUTE, 0);
+ showAnimation.setDuration(resources.getInteger(
+ android.R.integer.config_longAnimTime));
- showAnimation.setAnimationListener(new AnimationListener() {
- public void onAnimationEnd(Animation animation) {
- selectInitialTab();
- bindData();
- }
+ showAnimation.setAnimationListener(new AnimationListener() {
+ public void onAnimationEnd(Animation animation) {
+ selectInitialTab();
+ bindData();
+ }
- public void onAnimationRepeat(Animation animation) {
- }
+ public void onAnimationRepeat(Animation animation) {
+ }
- public void onAnimationStart(Animation animation) {
- }
+ public void onAnimationStart(Animation animation) {
+ }
- });
+ });
- mBelowHeader.startAnimation(showAnimation);
- }
+ mBelowHeader.startAnimation(showAnimation);
mTabWidget.setVisibility(View.VISIBLE);
mTabsVisible = true;
clearCurrentTabs();
bindTabs();
- if (!animate) {
- selectInitialTab();
- bindData();
- }
} else {
- if (animate) {
- TranslateAnimation hideTabsAnimation = new TranslateAnimation(
- Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 0,
- Animation.ABSOLUTE, 0, Animation.ABSOLUTE, -tabHeight);
- hideTabsAnimation.setDuration(getResources().getInteger(
- android.R.integer.config_longAnimTime));
- hideTabsAnimation.setAnimationListener(new AnimationListener() {
- public void onAnimationEnd(Animation animation) {
- bindData();
- }
+ TranslateAnimation hideTabsAnimation = new TranslateAnimation(
+ Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 0,
+ Animation.ABSOLUTE, 0, Animation.ABSOLUTE, -tabHeight);
+ hideTabsAnimation.setDuration(resources.getInteger(
+ android.R.integer.config_longAnimTime));
+ hideTabsAnimation.setAnimationListener(new AnimationListener() {
+ public void onAnimationEnd(Animation animation) {
+ bindData();
+ }
- public void onAnimationRepeat(Animation animation) {
- }
+ public void onAnimationRepeat(Animation animation) {
+ }
- public void onAnimationStart(Animation animation) {
- }
+ public void onAnimationStart(Animation animation) {
+ }
- });
+ });
- TranslateAnimation hideListAnimation = new TranslateAnimation(
- Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 0,
- Animation.ABSOLUTE, tabHeight, Animation.ABSOLUTE, 0);
- hideListAnimation.setDuration(getResources().getInteger(
- android.R.integer.config_longAnimTime));
+ TranslateAnimation hideListAnimation = new TranslateAnimation(
+ Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 0,
+ Animation.ABSOLUTE, tabHeight, Animation.ABSOLUTE, 0);
+ hideListAnimation.setDuration(resources.getInteger(
+ android.R.integer.config_longAnimTime));
- mTabWidget.startAnimation(hideTabsAnimation);
- mTabContentLayout.startAnimation(hideListAnimation);
- }
+ mTabWidget.startAnimation(hideTabsAnimation);
+ mTabContentLayout.startAnimation(hideListAnimation);
mTabWidget.setVisibility(View.GONE);
mTabsVisible = false;
mSelectedRawContactId = null;
- if (!animate) {
- bindData();
- }
}
}
@@ -459,9 +471,12 @@
boolean isAggregate = mEntities.size() > 1;
mContactHeaderWidget.showAggregateBadge(isAggregate);
if (mTabsVisible) {
+ mTabWidget.setVisibility(View.VISIBLE);
clearCurrentTabs();
bindTabs();
selectInitialTab();
+ } else {
+ mTabWidget.setVisibility(View.GONE);
}
bindData();
}
@@ -595,6 +610,7 @@
}
ViewEntry entry = ContactEntryAdapter.getEntry(mSections, info.position, SHOW_SEPARATORS);
+ menu.setHeaderTitle(R.string.contactOptionsTitle);
if (entry.mimetype.equals(CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) {
menu.add(0, 0, 0, R.string.menu_call).setIntent(entry.intent);
menu.add(0, 0, 0, R.string.menu_sendSMS).setIntent(entry.secondaryIntent);
@@ -619,11 +635,11 @@
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_show_sources: {
- showTabs(true, true /*animate*/);
+ showTabs(true);
break;
}
case R.id.menu_hide_sources: {
- showTabs(false, true /*animate*/);
+ showTabs(false);
break;
}
case R.id.menu_edit: {
@@ -638,7 +654,8 @@
}
Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI,
rawContactIdToEdit);
- startActivity(new Intent(Intent.ACTION_EDIT, rawContactUri));
+ startActivityForResult(new Intent(Intent.ACTION_EDIT, rawContactUri),
+ REQUEST_EDIT_CONTACT);
break;
}
case R.id.menu_delete: {
@@ -655,9 +672,13 @@
return true;
}
case R.id.menu_share: {
+ // TODO: Keep around actual LOOKUP_KEY, or formalize method of extracting
+ final String lookupKey = mLookupUri.getPathSegments().get(2);
+ final Uri shareUri = Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, lookupKey);
+
final Intent intent = new Intent(Intent.ACTION_SEND);
- intent.setType(Contacts.CONTENT_ITEM_TYPE);
- intent.putExtra(Intent.EXTRA_STREAM, mLookupUri);
+ intent.setType(Contacts.CONTENT_VCARD_TYPE);
+ intent.putExtra(Intent.EXTRA_STREAM, shareUri);
// Launch chooser to share contact via
final CharSequence chooseTitle = getText(R.string.share_via);
@@ -742,8 +763,15 @@
* Shows a list of aggregates that can be joined into the currently viewed aggregate.
*/
public void showJoinAggregateActivity() {
+ String displayName = null;
+ if (mCursor.moveToFirst()) {
+ displayName = mCursor.getString(0);
+ }
Intent intent = new Intent(ContactsListActivity.JOIN_AGGREGATE);
intent.putExtra(ContactsListActivity.EXTRA_AGGREGATE_ID, ContentUris.parseId(mUri));
+ if (displayName != null) {
+ intent.putExtra(ContactsListActivity.EXTRA_AGGREGATE_NAME, displayName);
+ }
startActivityForResult(intent, REQUEST_JOIN_CONTACT);
}
@@ -754,6 +782,8 @@
final long contactId = ContentUris.parseId(intent.getData());
joinAggregate(contactId);
}
+ } else if (requestCode == REQUEST_EDIT_CONTACT) {
+ mTabsVisible = false;
}
}
@@ -924,6 +954,12 @@
continue;
}
+ final ContactsSource source = sources.getInflatedSource(accountType,
+ ContactsSource.LEVEL_SUMMARY);
+ final String accountName = entValues.getAsString(RawContacts.ACCOUNT_NAME);
+ mAccountName.setText(getString(R.string.account_name_format,
+ source.getDisplayLabel(this), accountName));
+
for (NamedContentValues subValue : entity.getSubValues()) {
ViewEntry entry = new ViewEntry();
@@ -958,99 +994,88 @@
continue;
}
- if (CommonDataKinds.Phone.CONTENT_ITEM_TYPE.equals(mimetype)
- || CommonDataKinds.Email.CONTENT_ITEM_TYPE.equals(mimetype)
- || CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE.equals(mimetype)
- || CommonDataKinds.Im.CONTENT_ITEM_TYPE.equals(mimetype)) {
- final boolean isSuperPrimary = entryValues.getAsInteger(
- Data.IS_SUPER_PRIMARY) != 0;
+ final boolean isSuperPrimary = entryValues.getAsInteger(
+ Data.IS_SUPER_PRIMARY) != 0;
- if (CommonDataKinds.Phone.CONTENT_ITEM_TYPE.equals(mimetype)) {
- // Build phone entries
- mNumPhoneNumbers++;
+ if (CommonDataKinds.Phone.CONTENT_ITEM_TYPE.equals(mimetype)) {
+ // Build phone entries
+ mNumPhoneNumbers++;
- entry.intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
- Uri.fromParts("tel", entry.data, null));
- entry.secondaryIntent = new Intent(Intent.ACTION_SENDTO,
- Uri.fromParts("sms", entry.data, null));
- entry.data = PhoneNumberUtils.stripSeparators(entry.data);
+ entry.intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
+ Uri.fromParts("tel", entry.data, null));
+ entry.secondaryIntent = new Intent(Intent.ACTION_SENDTO,
+ Uri.fromParts("sms", entry.data, null));
+ entry.data = PhoneNumberUtils.stripSeparators(entry.data);
- // If data is empty, don't show it.
- if (TextUtils.isEmpty(entry.data)) {
- Log.w(TAG, "empty data for contact method " + id);
- continue;
+ entry.isPrimary = isSuperPrimary;
+ mPhoneEntries.add(entry);
+
+ if (entry.type == CommonDataKinds.Phone.TYPE_MOBILE
+ || mShowSmsLinksForAllPhones) {
+ // Add an SMS entry
+ if (kind.iconAltRes > 0) {
+ entry.secondaryActionIcon = kind.iconAltRes;
}
+ }
+ } else if (CommonDataKinds.Email.CONTENT_ITEM_TYPE.equals(mimetype)) {
+ // Build email entries
+ entry.intent = new Intent(Intent.ACTION_SENDTO,
+ Uri.fromParts("mailto", entry.data, null));
+ entry.isPrimary = isSuperPrimary;
+ mEmailEntries.add(entry);
+ } else if (CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE.
+ equals(mimetype)) {
+ // Build postal entries
+ entry.maxLines = 4;
+ entry.intent = new Intent(Intent.ACTION_VIEW, uri);
+ mPostalEntries.add(entry);
+ } else if (CommonDataKinds.Im.CONTENT_ITEM_TYPE.equals(mimetype)) {
+ // Build im entries
+ Object protocolObj = entryValues.getAsInteger(CommonDataKinds.Im.PROTOCOL);
+ String host = null;
- entry.isPrimary = isSuperPrimary;
- mPhoneEntries.add(entry);
+ if (TextUtils.isEmpty(entry.label)) {
+ entry.label = getString(R.string.chat).toLowerCase();
+ }
- if (entry.type == CommonDataKinds.Phone.TYPE_MOBILE
- || mShowSmsLinksForAllPhones) {
- // Add an SMS entry
- if (kind.iconAltRes > 0) {
- entry.secondaryActionIcon = kind.iconAltRes;
- }
+ if (protocolObj instanceof Number) {
+ int protocol = ((Number) protocolObj).intValue();
+ host = ContactsUtils.lookupProviderNameFromId(protocol);
+ if (protocol == CommonDataKinds.Im.PROTOCOL_GOOGLE_TALK
+ || protocol == CommonDataKinds.Im.PROTOCOL_MSN) {
+ entry.maxLabelLines = 2;
}
- } else if (CommonDataKinds.Email.CONTENT_ITEM_TYPE.equals(mimetype)) {
- // Build email entries
+ } else if (protocolObj != null) {
+ String providerName = (String) protocolObj;
+ host = providerName.toLowerCase();
+ }
+
+ // Only add the intent if there is a valid host
+ // host is null for CommonDataKinds.Im.PROTOCOL_CUSTOM
+ if (!TextUtils.isEmpty(host)) {
entry.intent = new Intent(Intent.ACTION_SENDTO,
- Uri.fromParts("mailto", entry.data, null));
- entry.isPrimary = isSuperPrimary;
- mEmailEntries.add(entry);
- } else if (CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE.
- equals(mimetype)) {
- // Build postal entries
- entry.maxLines = 4;
- entry.intent = new Intent(Intent.ACTION_VIEW, uri);
- mPostalEntries.add(entry);
- } else if (CommonDataKinds.Im.CONTENT_ITEM_TYPE.equals(mimetype)) {
- // Build im entries
- Object protocolObj = entryValues.getAsInteger(Data.DATA5);
- String host = null;
-
- if (TextUtils.isEmpty(entry.label)) {
- entry.label = getString(R.string.chat).toLowerCase();
- }
-
- if (protocolObj instanceof Number) {
- int protocol = ((Number) protocolObj).intValue();
- host = ContactsUtils.lookupProviderNameFromId(protocol);
- if (protocol == CommonDataKinds.Im.PROTOCOL_GOOGLE_TALK
- || protocol == CommonDataKinds.Im.PROTOCOL_MSN) {
- entry.maxLabelLines = 2;
- }
- } else if (protocolObj != null) {
- String providerName = (String) protocolObj;
- host = providerName.toLowerCase();
- }
-
- // Only add the intent if there is a valid host
- // host is null for CommonDataKinds.Im.PROTOCOL_CUSTOM
- if (!TextUtils.isEmpty(host)) {
- entry.intent = new Intent(Intent.ACTION_SENDTO,
- constructImToUrl(host.toLowerCase(), entry.data));
- }
- //TODO(emillar) Add in presence info
+ constructImToUrl(host.toLowerCase(), entry.data));
+ }
+ //TODO(emillar) Add in presence info
/*if (!aggCursor.isNull(METHODS_STATUS_COLUMN)) {
entry.presenceIcon = Presence.getPresenceIconResourceId(
aggCursor.getInt(METHODS_STATUS_COLUMN));
entry.status = ...
}*/
- mImEntries.add(entry);
- }
- } else if (CommonDataKinds.Organization.CONTENT_ITEM_TYPE.equals(mimetype)) {
- // Build organization entries
+ mImEntries.add(entry);
+ } else if (CommonDataKinds.Organization.CONTENT_ITEM_TYPE.equals(mimetype)
+ || CommonDataKinds.Nickname.CONTENT_ITEM_TYPE.equals(mimetype)) {
+ // Build organization and note entries
+ entry.uri = null;
mOrganizationEntries.add(entry);
} else if (CommonDataKinds.Note.CONTENT_ITEM_TYPE.equals(mimetype)) {
// Build note entries
- entry.id = 0;
entry.uri = null;
- entry.intent = null;
entry.maxLines = 10;
mOtherEntries.add(entry);
} else {
// Handle showing custom
- entry.intent = new Intent(Intent.ACTION_VIEW, uri);
+ entry.intent = new Intent(Intent.ACTION_VIEW, entry.uri);
mOtherEntries.add(entry);
}
@@ -1136,7 +1161,7 @@
/**
* A basic structure with the data for a contact entry in the list.
*/
- static class ViewEntry extends ContactEntryAdapter.Entry implements Collapsible<ViewEntry> {
+ class ViewEntry extends ContactEntryAdapter.Entry implements Collapsible<ViewEntry> {
public String resPackageName = null;
public int actionIcon = -1;
public boolean isPrimary = false;
@@ -1151,7 +1176,7 @@
public boolean collapseWith(ViewEntry entry) {
// assert equal collapse keys
- if (!getCollapseKey().equals(entry.getCollapseKey())) {
+ if (!shouldCollapseWith(entry)) {
return false;
}
@@ -1183,16 +1208,43 @@
return true;
}
- public String getCollapseKey() {
- StringBuilder hashSb = new StringBuilder();
- hashSb.append(data);
- hashSb.append(mimetype);
- hashSb.append((intent != null && intent.getAction() != null)
- ? intent.getAction() : "");
- hashSb.append((secondaryIntent != null && secondaryIntent.getAction() != null)
- ? secondaryIntent.getAction() : "");
- hashSb.append(actionIcon);
- return hashSb.toString();
+ public boolean shouldCollapseWith(ViewEntry entry) {
+ if (entry == null) {
+ return false;
+ }
+
+ if (Phone.CONTENT_ITEM_TYPE.equals(mimetype)
+ && Phone.CONTENT_ITEM_TYPE.equals(entry.mimetype)) {
+ if (!PhoneNumberUtils.compare(ViewContactActivity.this, data, entry.data)) {
+ return false;
+ }
+ } else {
+ if (!equals(data, entry.data)) {
+ return false;
+ }
+ }
+
+ if (!equals(mimetype, entry.mimetype)
+ || !intentCollapsible(intent, entry.intent)
+ || !intentCollapsible(secondaryIntent, entry.secondaryIntent)
+ || actionIcon != entry.actionIcon) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean equals(Object a, Object b) {
+ return a==b || (a != null && a.equals(b));
+ }
+
+ private boolean intentCollapsible(Intent a, Intent b) {
+ if (a == b) {
+ return true;
+ } else if ((a != null && b != null) && equals(a.getAction(), b.getAction())) {
+ return true;
+ }
+ return false;
}
}
diff --git a/src/com/android/contacts/model/Editor.java b/src/com/android/contacts/model/Editor.java
index d6f7003..b7ae045 100644
--- a/src/com/android/contacts/model/Editor.java
+++ b/src/com/android/contacts/model/Editor.java
@@ -49,7 +49,7 @@
* builds any needed views. Any changes performed by the user will be
* written back to that same object.
*/
- public void setValues(DataKind kind, ValuesDelta values, EntityDelta state);
+ public void setValues(DataKind kind, ValuesDelta values, EntityDelta state, boolean readOnly);
/**
* Add a specific {@link EditorListener} to this {@link Editor}.
diff --git a/src/com/android/contacts/model/EntityDelta.java b/src/com/android/contacts/model/EntityDelta.java
index 06c10d7..7ac0f5b 100644
--- a/src/com/android/contacts/model/EntityDelta.java
+++ b/src/com/android/contacts/model/EntityDelta.java
@@ -16,8 +16,6 @@
package com.android.contacts.model;
-import com.android.contacts.model.ContactsSource.DataKind;
-import com.android.contacts.model.ContactsSource.EditField;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
import com.google.android.collect.Sets;
@@ -34,7 +32,6 @@
import android.provider.ContactsContract;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
-import android.text.TextUtils;
import android.util.Log;
import android.view.View;
@@ -437,9 +434,10 @@
* or delete operations based on a "before" {@link Entity} snapshot.
*/
public static class ValuesDelta implements Parcelable {
- private ContentValues mBefore;
- private ContentValues mAfter;
- private String mIdColumn = BaseColumns._ID;
+ protected ContentValues mBefore;
+ protected ContentValues mAfter;
+ protected String mIdColumn = BaseColumns._ID;
+ private boolean mFromTemplate;
/**
* Next value to assign to {@link #mIdColumn} when building an insert
@@ -447,9 +445,9 @@
* we can concretely reference this {@link ValuesDelta} before it has
* been persisted.
*/
- private static int sNextInsertId = -1;
+ protected static int sNextInsertId = -1;
- private ValuesDelta() {
+ protected ValuesDelta() {
}
/**
@@ -507,6 +505,20 @@
}
}
+ public Integer getAsInteger(String key) {
+ return getAsInteger(key, null);
+ }
+
+ public Integer getAsInteger(String key, Integer defaultValue) {
+ if (mAfter != null && mAfter.containsKey(key)) {
+ return mAfter.getAsInteger(key);
+ } else if (mBefore != null && mBefore.containsKey(key)) {
+ return mBefore.getAsInteger(key);
+ } else {
+ return defaultValue;
+ }
+ }
+
public String getMimetype() {
return getAsString(Data.MIMETYPE);
}
@@ -532,6 +544,14 @@
return isPrimary == null ? false : isPrimary != 0;
}
+ public void setFromTemplate(boolean isFromTemplate) {
+ mFromTemplate = isFromTemplate;
+ }
+
+ public boolean isFromTemplate() {
+ return mFromTemplate;
+ }
+
public boolean beforeExists() {
return (mBefore != null && mBefore.containsKey(mIdColumn));
}
@@ -551,6 +571,11 @@
return beforeExists() && (mAfter != null && mAfter.size() > 0);
}
+ public boolean isNoop() {
+ // When "after" has no changes, action is no-op
+ return beforeExists() && (mAfter != null && mAfter.size() == 0);
+ }
+
public boolean isInsert() {
// When no "before" id, and has "after", action is "insert"
return !beforeExists() && (mAfter != null);
diff --git a/src/com/android/contacts/model/EntityModifier.java b/src/com/android/contacts/model/EntityModifier.java
index beaf3e6..d6f6571 100644
--- a/src/com/android/contacts/model/EntityModifier.java
+++ b/src/com/android/contacts/model/EntityModifier.java
@@ -389,7 +389,7 @@
// TODO: remove this verbose logging
Log.w(TAG, "Trimming: " + entry.toString());
entry.markDeleted();
- } else {
+ } else if (!entry.isFromTemplate()) {
hasValues = true;
}
}
diff --git a/src/com/android/contacts/model/ExchangeSource.java b/src/com/android/contacts/model/ExchangeSource.java
index 0a7fb23..6d4e357 100644
--- a/src/com/android/contacts/model/ExchangeSource.java
+++ b/src/com/android/contacts/model/ExchangeSource.java
@@ -125,8 +125,6 @@
.add(buildPhoneType(Phone.TYPE_RADIO).setSecondary(true).setSpecificMax(1));
kind.typeList.add(buildPhoneType(Phone.TYPE_ASSISTANT).setSecondary(true)
.setSpecificMax(1).setCustomColumn(Phone.LABEL));
- kind.typeList.add(buildPhoneType(Phone.TYPE_CUSTOM).setSecondary(true)
- .setSpecificMax(1).setCustomColumn(Phone.LABEL));
kind.fieldList = Lists.newArrayList();
kind.fieldList.add(new EditField(Phone.NUMBER, R.string.phoneLabelsGroup, FLAGS_PHONE));
diff --git a/src/com/android/contacts/model/GoogleSource.java b/src/com/android/contacts/model/GoogleSource.java
index 9968ace..b6f1e29 100644
--- a/src/com/android/contacts/model/GoogleSource.java
+++ b/src/com/android/contacts/model/GoogleSource.java
@@ -42,7 +42,6 @@
public class GoogleSource extends FallbackSource {
public static final String ACCOUNT_TYPE = "com.google.GAIA";
-
public GoogleSource(String resPackageName) {
this.accountType = ACCOUNT_TYPE;
this.resPackageName = null;
@@ -160,6 +159,7 @@
public static final void attemptMyContactsMembership(EntityDelta state, Context context) {
final ValuesDelta stateValues = state.getValues();
+ stateValues.setFromTemplate(true);
final String accountName = stateValues.getAsString(RawContacts.ACCOUNT_NAME);
final String accountType = stateValues.getAsString(RawContacts.ACCOUNT_TYPE);
attemptMyContactsMembership(state, accountName, accountType, context, true);
diff --git a/src/com/android/contacts/model/Sources.java b/src/com/android/contacts/model/Sources.java
index 04fa493..7d06cab 100644
--- a/src/com/android/contacts/model/Sources.java
+++ b/src/com/android/contacts/model/Sources.java
@@ -24,6 +24,7 @@
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorDescription;
+import android.accounts.OnAccountsUpdatedListener;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -46,10 +47,11 @@
* Singleton holder for all parsed {@link ContactsSource} available on the
* system, typically filled through {@link PackageManager} queries.
*/
-public class Sources extends BroadcastReceiver {
+public class Sources extends BroadcastReceiver implements OnAccountsUpdatedListener {
private static final String TAG = "Sources";
- private Context mContext;
+ private Context mApplicationContext;
+ private AccountManager mAccountManager;
private ContactsSource mFallbackSource = null;
@@ -76,13 +78,22 @@
* Internal constructor that only performs initial parsing.
*/
private Sources(Context context) {
- mContext = context;
+ mApplicationContext = context.getApplicationContext();
+ mAccountManager = AccountManager.get(mApplicationContext);
// Create fallback contacts source for on-phone contacts
mFallbackSource = new FallbackSource();
- loadAccounts();
- registerIntentReceivers(context);
+ queryAccounts();
+
+ // Request updates when packages or accounts change
+ final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addDataScheme("package");
+
+ mApplicationContext.registerReceiver(this, filter);
+ mAccountManager.addOnAccountsUpdatedListener(this, null, false);
}
/** @hide exposed for unit tests */
@@ -97,49 +108,50 @@
mKnownPackages.add(source.resPackageName);
}
- private void registerIntentReceivers(Context context) {
- IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- filter.addDataScheme("package");
-
- // We use getApplicationContext() so that the broadcast reciever can stay registered for
- // the length of the application lifetime (instead of the calling activity's lifetime).
- // This is so that we can notified of package changes, and purge the cache accordingly,
- // but not be woken up if the application process isn't already running, since we will
- // have no cache to clear at that point.
- context.getApplicationContext().registerReceiver(this, filter);
- }
-
/** {@inheritDoc} */
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
final String packageName = intent.getData().getSchemeSpecificPart();
- final boolean matchingPackage = mKnownPackages.contains(packageName);
- final boolean validAction = Intent.ACTION_PACKAGE_REMOVED.equals(action)
+ if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
|| Intent.ACTION_PACKAGE_ADDED.equals(action)
- || Intent.ACTION_PACKAGE_CHANGED.equals(action);
-
- if (matchingPackage && validAction) {
- for (ContactsSource source : mSources.values()) {
- if (TextUtils.equals(packageName, source.resPackageName)) {
- // Invalidate any cache for the changed package
- source.invalidateCache();
- }
+ || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
+ final boolean knownPackage = mKnownPackages.contains(packageName);
+ if (knownPackage) {
+ // Invalidate cache of existing source
+ invalidateCache(packageName);
+ } else {
+ // Unknown source, so reload from scratch
+ queryAccounts();
}
}
}
+ protected void invalidateCache(String packageName) {
+ for (ContactsSource source : mSources.values()) {
+ if (TextUtils.equals(packageName, source.resPackageName)) {
+ // Invalidate any cache for the changed package
+ source.invalidateCache();
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void onAccountsUpdated(Account[] accounts) {
+ // Refresh to catch any changed accounts
+ queryAccounts();
+ }
+
/**
* Blocking call to load all {@link AuthenticatorDescription} known by the
* {@link AccountManager} on the system.
*/
- protected void loadAccounts() {
+ protected synchronized void queryAccounts() {
mSources.clear();
+ mKnownPackages.clear();
- final AccountManager am = AccountManager.get(mContext);
+ final AccountManager am = mAccountManager;
final IContentService cs = ContentResolver.getContentService();
try {
@@ -200,7 +212,7 @@
* returned may require inflation before they can be used.
*/
public ArrayList<Account> getAccounts(boolean writableOnly) {
- final AccountManager am = AccountManager.get(mContext);
+ final AccountManager am = mAccountManager;
final Account[] accounts = am.getAccounts();
final ArrayList<Account> matching = Lists.newArrayList();
@@ -259,7 +271,7 @@
return source;
} else {
// Not inflated, but requested that we force-inflate
- source.ensureInflated(mContext, inflateLevel);
+ source.ensureInflated(mApplicationContext, inflateLevel);
return source;
}
}
diff --git a/src/com/android/contacts/ui/DisplayGroupsActivity.java b/src/com/android/contacts/ui/DisplayGroupsActivity.java
index 69f0007..7bd7b9d 100644
--- a/src/com/android/contacts/ui/DisplayGroupsActivity.java
+++ b/src/com/android/contacts/ui/DisplayGroupsActivity.java
@@ -17,38 +17,39 @@
package com.android.contacts.ui;
import com.android.contacts.R;
-import com.android.contacts.model.GoogleSource;
import com.android.contacts.model.ContactsSource;
+import com.android.contacts.model.GoogleSource;
import com.android.contacts.model.Sources;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
import com.android.contacts.util.EmptyService;
import com.android.contacts.util.WeakAsyncTask;
-import com.google.android.collect.Sets;
+import com.google.android.collect.Lists;
import android.accounts.Account;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ExpandableListActivity;
import android.app.ProgressDialog;
+import android.content.ContentProviderOperation;
import android.content.ContentResolver;
-import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.EntityIterator;
import android.content.Intent;
+import android.content.OperationApplicationException;
import android.content.SharedPreferences;
+import android.content.ContentProviderOperation.Builder;
import android.content.SharedPreferences.Editor;
-import android.content.pm.PackageManager;
-import android.database.AbstractCursor;
import android.database.Cursor;
-import android.database.CursorWrapper;
-import android.database.MergeCursor;
import android.net.Uri;
import android.os.Bundle;
+import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.provider.ContactsContract;
-import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Groups;
import android.provider.ContactsContract.Settings;
+import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MenuItem;
@@ -56,8 +57,8 @@
import android.view.ViewGroup;
import android.view.MenuItem.OnMenuItemClickListener;
import android.widget.AdapterView;
+import android.widget.BaseExpandableListAdapter;
import android.widget.CheckBox;
-import android.widget.CursorTreeAdapter;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.TextView;
@@ -65,21 +66,18 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
/**
* Shows a list of all available {@link Groups} available, letting the user
* select which ones they want to be visible.
*/
public final class DisplayGroupsActivity extends ExpandableListActivity implements
- AdapterView.OnItemClickListener {
+ AdapterView.OnItemClickListener, View.OnClickListener {
private static final String TAG = "DisplayGroupsActivity";
- private static final int UNGROUPED_ID = -2;
- private static final int UNSYNCED_ID = -3;
-
- private static final int FOOTER_ENTRY = -4;
-
public interface Prefs {
public static final String DISPLAY_ONLY_PHONES = "only_phones";
public static final boolean DISPLAY_ONLY_PHONES_DEFAULT = false;
@@ -87,7 +85,7 @@
}
private ExpandableListView mList;
- private DisplayGroupsAdapter mAdapter;
+ private DisplayAdapter mAdapter;
private SharedPreferences mPrefs;
@@ -96,16 +94,10 @@
private View mHeaderPhones;
private View mHeaderSeparator;
- private static final Uri sDelayedSettings = Settings.CONTENT_URI.buildUpon()
- .appendQueryParameter(Contacts.DELAY_STARRED_UPDATE, "1").build();
-
- private static final Uri sDelayedGroups = Groups.CONTENT_URI.buildUpon()
- .appendQueryParameter(Contacts.DELAY_STARRED_UPDATE, "1").build();
-
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
- setContentView(android.R.layout.expandable_list_content);
+ setContentView(R.layout.act_display_groups);
mList = getExpandableListView();
mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
@@ -116,6 +108,8 @@
mHeaderPhones = inflater.inflate(R.layout.display_header, mList, false);
mHeaderPhones.setId(R.id.header_phones);
mDisplayPhones = (CheckBox) mHeaderPhones.findViewById(android.R.id.checkbox);
+ mDisplayPhones.setChecked(mPrefs.getBoolean(Prefs.DISPLAY_ONLY_PHONES,
+ Prefs.DISPLAY_ONLY_PHONES_DEFAULT));
{
final TextView text1 = (TextView)mHeaderPhones.findViewById(android.R.id.text1);
final TextView text2 = (TextView)mHeaderPhones.findViewById(android.R.id.text2);
@@ -124,7 +118,6 @@
}
mList.addHeaderView(mHeaderPhones, null, true);
-
// Add the separator before showing the detailed group list.
mHeaderSeparator = inflater.inflate(R.layout.list_separator, mList, false);
{
@@ -133,91 +126,484 @@
}
mList.addHeaderView(mHeaderSeparator, null, false);
- mAdapter = new DisplayGroupsAdapter(null, this, this);
-
- boolean displayOnlyPhones = mPrefs.getBoolean(Prefs.DISPLAY_ONLY_PHONES,
- Prefs.DISPLAY_ONLY_PHONES_DEFAULT);
-
- mDisplayPhones.setChecked(displayOnlyPhones);
-
- mAdapter.setChildDescripWithPhones(displayOnlyPhones);
-
- setListAdapter(mAdapter);
+ findViewById(R.id.btn_done).setOnClickListener(this);
+ findViewById(R.id.btn_discard).setOnClickListener(this);
// Catch clicks on the header views
mList.setOnItemClickListener(this);
mList.setOnCreateContextMenuListener(this);
// Start background query to find account details
- new QuerySettingsTask(this).execute();
+ new QueryGroupsTask(this).execute();
}
- private static class QuerySettingsTask extends
- WeakAsyncTask<Void, Void, Cursor, DisplayGroupsActivity> {
- public QuerySettingsTask(DisplayGroupsActivity target) {
+ /**
+ * Background operation to build set of {@link AccountDisplay} for each
+ * {@link Sources#getAccounts(boolean)} that provides groups.
+ */
+ private static class QueryGroupsTask extends
+ WeakAsyncTask<Void, Void, AccountSet, DisplayGroupsActivity> {
+ public QueryGroupsTask(DisplayGroupsActivity target) {
super(target);
}
@Override
- protected Cursor doInBackground(DisplayGroupsActivity target, Void... params) {
+ protected AccountSet doInBackground(DisplayGroupsActivity target,
+ Void... params) {
final Context context = target;
final Sources sources = Sources.getInstance(context);
-
- // Query to find Settings for all data sources
final ContentResolver resolver = context.getContentResolver();
- final Cursor cursor = resolver.query(ContactsContract.Settings.CONTENT_URI,
- SettingsQuery.PROJECTION, null, null, null);
- target.startManagingCursor(cursor);
- // Make records for each account known by Settings
- final HashSet<Account> knownAccounts = Sets.newHashSet();
- while (cursor.moveToNext()) {
- final String accountName = cursor.getString(SettingsQuery.ACCOUNT_NAME);
- final String accountType = cursor.getString(SettingsQuery.ACCOUNT_TYPE);
- final Account account = new Account(accountName, accountType);
- knownAccounts.add(account);
+ // Inflate groups entry for each account
+ final AccountSet accounts = new AccountSet();
+ for (Account account : sources.getAccounts(false)) {
+ accounts.add(new AccountDisplay(resolver, account.name, account.type));
}
- // Assert that Settings exist for each data source
- boolean changedSettings = false;
- final ArrayList<Account> expectedAccounts = sources.getAccounts(false);
- for (Account account : expectedAccounts) {
- if (!knownAccounts.contains(account)) {
- // Expected account that doesn't exist yet in Settings
- final ContentValues values = new ContentValues();
- values.put(Settings.ACCOUNT_NAME, account.name);
- values.put(Settings.ACCOUNT_TYPE, account.type);
- resolver.insert(Settings.CONTENT_URI, values);
-
- // Make sure we requery to catch this insert
- changedSettings = true;
- }
- }
-
- if (changedSettings) {
- // Catch any new sources discovered above
- cursor.requery();
- }
-
- // Wrap cursor to provide _id column
- final Cursor settingsCursor = new CursorWrapper(cursor) {
- @Override
- public long getLong(int columnIndex) {
- if (columnIndex == -1) {
- return this.getPosition();
- } else {
- return super.getLong(columnIndex);
- }
- }
- };
-
- return settingsCursor;
+ return accounts;
}
@Override
- protected void onPostExecute(DisplayGroupsActivity target, Cursor result) {
- // Update cursor for data sources
- target.mAdapter.setGroupCursor(result);
+ protected void onPostExecute(DisplayGroupsActivity target, AccountSet result) {
+ // Build adapter to show available groups
+ final Context context = target;
+ final DisplayAdapter adapter = new DisplayAdapter(context, result);
+ target.setListAdapter(adapter);
+ }
+ }
+
+ public void setListAdapter(DisplayAdapter adapter) {
+ mAdapter = adapter;
+ mAdapter.setChildDescripWithPhones(mDisplayPhones.isChecked());
+ super.setListAdapter(mAdapter);
+ }
+
+ private static final int DEFAULT_SHOULD_SYNC = 1;
+ private static final int DEFAULT_VISIBLE = 0;
+
+ /**
+ * Entry holding any changes to {@link Groups} or {@link Settings} rows,
+ * such as {@link Groups#SHOULD_SYNC} or {@link Groups#GROUP_VISIBLE}.
+ */
+ protected static class GroupDelta extends ValuesDelta {
+ private boolean mUngrouped = false;
+ private boolean mAccountHasGroups;
+
+ private GroupDelta() {
+ super();
+ }
+
+ /**
+ * Build {@link GroupDelta} from the {@link Settings} row for the given
+ * {@link Settings#ACCOUNT_NAME} and {@link Settings#ACCOUNT_TYPE}.
+ */
+ public static GroupDelta fromSettings(ContentResolver resolver, String accountName,
+ String accountType, boolean accountHasGroups) {
+ final Uri settingsUri = Settings.CONTENT_URI.buildUpon()
+ .appendQueryParameter(Settings.ACCOUNT_NAME, accountName)
+ .appendQueryParameter(Settings.ACCOUNT_TYPE, accountType).build();
+ final Cursor cursor = resolver.query(settingsUri, new String[] {
+ Settings.SHOULD_SYNC, Settings.UNGROUPED_VISIBLE
+ }, null, null, null);
+
+ try {
+ final ContentValues values = new ContentValues();
+ values.put(Settings.ACCOUNT_NAME, accountName);
+ values.put(Settings.ACCOUNT_TYPE, accountType);
+
+ if (cursor != null && cursor.moveToFirst()) {
+ // Read existing values when present
+ values.put(Settings.SHOULD_SYNC, cursor.getInt(0));
+ values.put(Settings.UNGROUPED_VISIBLE, cursor.getInt(1));
+ return fromBefore(values).setUngrouped(accountHasGroups);
+ } else {
+ // Nothing found, so treat as create
+ values.put(Settings.SHOULD_SYNC, DEFAULT_SHOULD_SYNC);
+ values.put(Settings.UNGROUPED_VISIBLE, DEFAULT_VISIBLE);
+ return fromAfter(values).setUngrouped(accountHasGroups);
+ }
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ }
+
+ public static GroupDelta fromBefore(ContentValues before) {
+ final GroupDelta entry = new GroupDelta();
+ entry.mBefore = before;
+ entry.mAfter = new ContentValues();
+ return entry;
+ }
+
+ public static GroupDelta fromAfter(ContentValues after) {
+ final GroupDelta entry = new GroupDelta();
+ entry.mBefore = null;
+ entry.mAfter = after;
+ return entry;
+ }
+
+ protected GroupDelta setUngrouped(boolean accountHasGroups) {
+ mUngrouped = true;
+ mAccountHasGroups = accountHasGroups;
+ return this;
+ }
+
+ @Override
+ public boolean beforeExists() {
+ return mBefore != null;
+ }
+
+ public boolean getShouldSync() {
+ return getAsInteger(mUngrouped ? Settings.SHOULD_SYNC : Groups.SHOULD_SYNC,
+ DEFAULT_SHOULD_SYNC) != 0;
+ }
+
+ public boolean getVisible() {
+ return getAsInteger(mUngrouped ? Settings.UNGROUPED_VISIBLE : Groups.GROUP_VISIBLE,
+ DEFAULT_VISIBLE) != 0;
+ }
+
+ public void putShouldSync(boolean shouldSync) {
+ put(mUngrouped ? Settings.SHOULD_SYNC : Groups.SHOULD_SYNC, shouldSync ? 1 : 0);
+ }
+
+ public void putVisible(boolean visible) {
+ put(mUngrouped ? Settings.UNGROUPED_VISIBLE : Groups.GROUP_VISIBLE, visible ? 1 : 0);
+ }
+
+ public CharSequence getTitle(Context context) {
+ if (mUngrouped) {
+ if (mAccountHasGroups) {
+ return context.getText(R.string.display_ungrouped);
+ } else {
+ return context.getText(R.string.display_all_contacts);
+ }
+ } else {
+ final Integer titleRes = getAsInteger(Groups.TITLE_RES);
+ if (titleRes != null) {
+ final String packageName = getAsString(Groups.RES_PACKAGE);
+ return context.getPackageManager().getText(packageName, titleRes, null);
+ } else {
+ return getAsString(Groups.TITLE);
+ }
+ }
+ }
+
+ /**
+ * Build a possible {@link ContentProviderOperation} to persist any
+ * changes to the {@link Groups} or {@link Settings} row described by
+ * this {@link GroupDelta}.
+ */
+ public ContentProviderOperation buildDiff() {
+ if (isNoop()) {
+ return null;
+ } else if (isUpdate()) {
+ // When has changes and "before" exists, then "update"
+ final Builder builder = ContentProviderOperation
+ .newUpdate(mUngrouped ? Settings.CONTENT_URI : Groups.CONTENT_URI);
+ if (mUngrouped) {
+ builder.withSelection(Settings.ACCOUNT_NAME + "=? AND " + Settings.ACCOUNT_TYPE
+ + "=?", new String[] {
+ this.getAsString(Settings.ACCOUNT_NAME),
+ this.getAsString(Settings.ACCOUNT_TYPE)
+ });
+ } else {
+ builder.withSelection(Groups._ID + "=" + this.getId(), null);
+ }
+ builder.withValues(mAfter);
+ return builder.build();
+ } else if (isInsert() && mUngrouped) {
+ // Only allow inserts for Settings
+ mAfter.remove(mIdColumn);
+ final Builder builder = ContentProviderOperation.newInsert(Settings.CONTENT_URI);
+ builder.withValues(mAfter);
+ return builder.build();
+ } else {
+ throw new IllegalStateException("Unexpected delete or insert");
+ }
+ }
+ }
+
+ /**
+ * {@link Comparator} to sort by {@link Groups#_ID}.
+ */
+ private static Comparator<GroupDelta> sIdComparator = new Comparator<GroupDelta>() {
+ public int compare(GroupDelta object1, GroupDelta object2) {
+ return object1.getViewId() - object2.getViewId();
+ }
+ };
+
+ /**
+ * Set of all {@link AccountDisplay} entries, one for each source.
+ */
+ protected static class AccountSet extends ArrayList<AccountDisplay> {
+ public ArrayList<ContentProviderOperation> buildDiff() {
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ for (AccountDisplay account : this) {
+ account.buildDiff(diff);
+ }
+ return diff;
+ }
+ }
+
+ /**
+ * {@link GroupDelta} details for a single {@link Account}, usually shown as
+ * children under a single expandable group.
+ */
+ protected static class AccountDisplay {
+ public String mName;
+ public String mType;
+
+ public GroupDelta mUngrouped;
+ public ArrayList<GroupDelta> mSyncedGroups = Lists.newArrayList();
+ public ArrayList<GroupDelta> mUnsyncedGroups = Lists.newArrayList();
+
+ /**
+ * Build an {@link AccountDisplay} covering all {@link Groups} under the
+ * given {@link Account}.
+ */
+ public AccountDisplay(ContentResolver resolver, String accountName, String accountType) {
+ mName = accountName;
+ mType = accountType;
+
+ boolean hasGroups = false;
+
+ final Uri groupsUri = Groups.CONTENT_URI.buildUpon()
+ .appendQueryParameter(Groups.ACCOUNT_NAME, accountName)
+ .appendQueryParameter(Groups.ACCOUNT_TYPE, accountType).build();
+ EntityIterator iterator = null;
+ try {
+ // Create entries for each known group
+ iterator = resolver.queryEntities(groupsUri, null, null, null);
+ while (iterator.hasNext()) {
+ final ContentValues values = iterator.next().getEntityValues();
+ final GroupDelta group = GroupDelta.fromBefore(values);
+ addGroup(group);
+ hasGroups = true;
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Problem reading groups: " + e.toString());
+ } finally {
+ if (iterator != null) iterator.close();
+ }
+
+ // Create single entry handling ungrouped status
+ mUngrouped = GroupDelta.fromSettings(resolver, accountName, accountType, hasGroups);
+ addGroup(mUngrouped);
+ }
+
+ /**
+ * Add the given {@link GroupDelta} internally, filing based on its
+ * {@link GroupDelta#getShouldSync()} status.
+ */
+ private void addGroup(GroupDelta group) {
+ if (group.getShouldSync()) {
+ mSyncedGroups.add(group);
+ } else {
+ mUnsyncedGroups.add(group);
+ }
+ }
+
+ /**
+ * Set the {@link GroupDelta#putShouldSync(boolean)} value for all
+ * children {@link GroupDelta} rows.
+ */
+ public void setShouldSync(boolean shouldSync) {
+ final Iterator<GroupDelta> oppositeChildren = shouldSync ?
+ mUnsyncedGroups.iterator() : mSyncedGroups.iterator();
+ while (oppositeChildren.hasNext()) {
+ final GroupDelta child = oppositeChildren.next();
+ setShouldSync(child, shouldSync, false);
+ oppositeChildren.remove();
+ }
+ }
+
+ public void setShouldSync(GroupDelta child, boolean shouldSync) {
+ setShouldSync(child, shouldSync, true);
+ }
+
+ /**
+ * Set {@link GroupDelta#putShouldSync(boolean)}, and file internally
+ * based on updated state.
+ */
+ public void setShouldSync(GroupDelta child, boolean shouldSync, boolean attemptRemove) {
+ child.putShouldSync(shouldSync);
+ if (shouldSync) {
+ if (attemptRemove) {
+ mUnsyncedGroups.remove(child);
+ }
+ mSyncedGroups.add(child);
+ Collections.sort(mSyncedGroups, sIdComparator);
+ } else {
+ if (attemptRemove) {
+ mSyncedGroups.remove(child);
+ }
+ mUnsyncedGroups.add(child);
+ }
+ }
+
+ /**
+ * Build set of {@link ContentProviderOperation} to persist any user
+ * changes to {@link GroupDelta} rows under this {@link Account}.
+ */
+ public void buildDiff(ArrayList<ContentProviderOperation> diff) {
+ for (GroupDelta group : mSyncedGroups) {
+ final ContentProviderOperation oper = group.buildDiff();
+ if (oper != null) diff.add(oper);
+ }
+ for (GroupDelta group : mUnsyncedGroups) {
+ final ContentProviderOperation oper = group.buildDiff();
+ if (oper != null) diff.add(oper);
+ }
+ }
+ }
+
+ /**
+ * {@link ExpandableListAdapter} that shows {@link GroupDelta} settings,
+ * grouped by {@link Account} source. Shows footer row when any groups are
+ * unsynced, as determined through {@link AccountDisplay#mUnsyncedGroups}.
+ */
+ protected static class DisplayAdapter extends BaseExpandableListAdapter {
+ private Context mContext;
+ private LayoutInflater mInflater;
+ private Sources mSources;
+
+ private AccountSet mAccounts;
+
+ private boolean mChildWithPhones = false;
+
+ public DisplayAdapter(Context context, AccountSet accounts) {
+ mContext = context;
+ mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mSources = Sources.getInstance(context);
+
+ mAccounts = accounts;
+ }
+
+ /**
+ * In group descriptions, show the number of contacts with phone
+ * numbers, in addition to the total contacts.
+ */
+ public void setChildDescripWithPhones(boolean withPhones) {
+ mChildWithPhones = withPhones;
+ }
+
+ /** {@inheritDoc} */
+ public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
+ View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = mInflater.inflate(R.layout.display_child, parent, false);
+ }
+
+ final TextView text1 = (TextView)convertView.findViewById(android.R.id.text1);
+ final TextView text2 = (TextView)convertView.findViewById(android.R.id.text2);
+ final CheckBox checkbox = (CheckBox)convertView.findViewById(android.R.id.checkbox);
+
+ final AccountDisplay account = mAccounts.get(groupPosition);
+ final GroupDelta child = (GroupDelta)this.getChild(groupPosition, childPosition);
+ if (child != null) {
+ // Handle normal group, with title and checkbox
+ final boolean groupVisible = child.getVisible();
+ checkbox.setVisibility(View.VISIBLE);
+ checkbox.setChecked(groupVisible);
+
+ final CharSequence groupTitle = child.getTitle(mContext);
+ text1.setText(groupTitle);
+
+// final int count = cursor.getInt(GroupsQuery.SUMMARY_COUNT);
+// final int withPhones = cursor.getInt(GroupsQuery.SUMMARY_WITH_PHONES);
+
+// final CharSequence descrip = mContext.getResources().getQuantityString(
+// mChildWithPhones ? R.plurals.groupDescripPhones : R.plurals.groupDescrip,
+// count, count, withPhones);
+
+// text2.setText(descrip);
+ text2.setVisibility(View.GONE);
+ } else {
+ // When unknown child, this is "more" footer view
+ checkbox.setVisibility(View.GONE);
+ text1.setText(R.string.display_more_groups);
+ text2.setVisibility(View.GONE);
+ }
+
+ return convertView;
+ }
+
+ /** {@inheritDoc} */
+ public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
+ ViewGroup parent) {
+ if (convertView == null) {
+ convertView = mInflater.inflate(R.layout.display_group, parent, false);
+ }
+
+ final TextView text1 = (TextView)convertView.findViewById(android.R.id.text1);
+ final TextView text2 = (TextView)convertView.findViewById(android.R.id.text2);
+
+ final AccountDisplay account = (AccountDisplay)this.getGroup(groupPosition);
+
+ final ContactsSource source = mSources.getInflatedSource(account.mType,
+ ContactsSource.LEVEL_SUMMARY);
+
+ text1.setText(account.mName);
+ text2.setText(source.getDisplayLabel(mContext));
+ text2.setVisibility(account.mName == null ? View.GONE : View.VISIBLE);
+
+ return convertView;
+ }
+
+ /** {@inheritDoc} */
+ public Object getChild(int groupPosition, int childPosition) {
+ final AccountDisplay account = mAccounts.get(groupPosition);
+ final boolean validChild = childPosition >= 0
+ && childPosition < account.mSyncedGroups.size();
+ if (validChild) {
+ return account.mSyncedGroups.get(childPosition);
+ } else {
+ return null;
+ }
+ }
+
+ /** {@inheritDoc} */
+ public long getChildId(int groupPosition, int childPosition) {
+ final GroupDelta child = (GroupDelta)getChild(groupPosition, childPosition);
+ if (child != null) {
+ final Long childId = child.getId();
+ return childId != null ? childId : Long.MIN_VALUE;
+ } else {
+ return Long.MIN_VALUE;
+ }
+ }
+
+ /** {@inheritDoc} */
+ public int getChildrenCount(int groupPosition) {
+ // Count is any synced groups, plus possible footer
+ final AccountDisplay account = mAccounts.get(groupPosition);
+ final boolean anyHidden = account.mUnsyncedGroups.size() > 0;
+ return account.mSyncedGroups.size() + (anyHidden ? 1 : 0);
+ }
+
+ /** {@inheritDoc} */
+ public Object getGroup(int groupPosition) {
+ return mAccounts.get(groupPosition);
+ }
+
+ /** {@inheritDoc} */
+ public int getGroupCount() {
+ return mAccounts.size();
+ }
+
+ /** {@inheritDoc} */
+ public long getGroupId(int groupPosition) {
+ return groupPosition;
+ }
+
+ /** {@inheritDoc} */
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ public boolean isChildSelectable(int groupPosition, int childPosition) {
+ return true;
}
}
@@ -229,7 +615,20 @@
switch (view.getId()) {
case R.id.header_phones: {
mDisplayPhones.toggle();
- setDisplayOnlyPhones(mDisplayPhones.isChecked());
+ break;
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.btn_done: {
+ this.doSaveAction();
+ break;
+ }
+ case R.id.btn_discard: {
+ this.finish();
break;
}
}
@@ -255,36 +654,19 @@
* usually mean toggling its visible state.
*/
@Override
- public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
+ public boolean onChildClick(ExpandableListView parent, View view, int groupPosition,
int childPosition, long id) {
- final CheckBox checkbox = (CheckBox)v.findViewById(android.R.id.checkbox);
- checkbox.toggle();
+ final CheckBox checkbox = (CheckBox)view.findViewById(android.R.id.checkbox);
- // Build visibility update and send down to database
- final ContentResolver resolver = getContentResolver();
- final ContentValues values = new ContentValues();
-
- if (id == UNGROUPED_ID) {
- // Handle persisting for ungrouped through Settings
- values.put(Settings.UNGROUPED_VISIBLE, checkbox.isChecked() ? 1 : 0);
-
- final Cursor settings = mAdapter.getGroup(groupPosition);
- final int count = resolver.update(sDelayedSettings, values, Groups.ACCOUNT_NAME
- + "=? AND " + Groups.ACCOUNT_TYPE + "=?", new String[] {
- settings.getString(SettingsQuery.ACCOUNT_NAME),
- settings.getString(SettingsQuery.ACCOUNT_TYPE)
- });
- } else if (id == UNSYNCED_ID) {
- // Open context menu for bringing back unsynced
- this.openContextMenu(v);
+ final AccountDisplay account = (AccountDisplay)mAdapter.getGroup(groupPosition);
+ final GroupDelta child = (GroupDelta)mAdapter.getChild(groupPosition, childPosition);
+ if (child != null) {
+ checkbox.toggle();
+ child.putVisible(checkbox.isChecked());
} else {
- // Handle persisting for normal group
- values.put(Groups.GROUP_VISIBLE, checkbox.isChecked() ? 1 : 0);
-
- final Uri groupUri = ContentUris.withAppendedId(sDelayedGroups, id);
- final int count = resolver.update(groupUri, values, null, null);
+ // Open context menu for bringing back unsynced
+ this.openContextMenu(view);
}
-
return true;
}
@@ -294,9 +676,19 @@
private static final int SYNC_MODE_UNGROUPED = 1;
private static final int SYNC_MODE_EVERYTHING = 2;
+ protected int getSyncMode(AccountDisplay account) {
+ // TODO: read sync mode through <sync-adapter> definition
+ if (GoogleSource.ACCOUNT_TYPE.equals(account.mType)) {
+ return SYNC_MODE_EVERYTHING;
+ } else {
+ return SYNC_MODE_UNSUPPORTED;
+ }
+ }
+
@Override
- public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, v, menuInfo);
+ public void onCreateContextMenu(ContextMenu menu, View view,
+ ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, view, menuInfo);
// Bail if not working with expandable long-press, or if not child
if (!(menuInfo instanceof ExpandableListContextMenuInfo)) return;
@@ -305,54 +697,42 @@
final int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
final int childPosition = ExpandableListView.getPackedPositionChild(info.packedPosition);
- final Cursor groupCursor = mAdapter.getGroup(groupPosition);
- final String accountName = groupCursor.getString(SettingsQuery.ACCOUNT_NAME);
- final String accountType = groupCursor.getString(SettingsQuery.ACCOUNT_TYPE);
+ // Skip long-press on expandable parents
+ if (childPosition == -1) return;
- // TODO: read sync mode through <sync-adapter> definition
- int syncMode = SYNC_MODE_UNSUPPORTED;
- if (accountType.equals(GoogleSource.ACCOUNT_TYPE)) {
- syncMode = SYNC_MODE_EVERYTHING;
- }
+ final AccountDisplay account = (AccountDisplay)mAdapter.getGroup(groupPosition);
+ final GroupDelta child = (GroupDelta)mAdapter.getChild(groupPosition, childPosition);
// Ignore when selective syncing unsupported
+ final int syncMode = getSyncMode(account);
if (syncMode == SYNC_MODE_UNSUPPORTED) return;
- final Account account = new Account(accountName, accountType);
-
- final boolean shouldSyncUngrouped = groupCursor.getInt(SettingsQuery.SHOULD_SYNC) != 0;
- final boolean anyUnsynced = groupCursor.getInt(SettingsQuery.ANY_UNSYNCED) != 0;
- final boolean lastChild = (childPosition == (mAdapter.getChildrenCount(groupPosition) - 1));
-
- if (anyUnsynced && lastChild) {
- // Show add dialog for this overall source
- showAddSync(menu, groupCursor, account, syncMode);
-
- } else if (childPosition != -1) {
- // Show remove dialog for this specific group
- final Cursor childCursor = mAdapter.getChild(groupPosition, childPosition);
- showRemoveSync(menu, account, childCursor, syncMode, shouldSyncUngrouped);
+ if (child != null) {
+ showRemoveSync(menu, account, child, syncMode);
+ } else {
+ showAddSync(menu, account, syncMode);
}
}
- protected void showRemoveSync(ContextMenu menu, final Account account, Cursor childCursor,
- final int syncMode, final boolean shouldSyncUngrouped) {
- final long groupId = childCursor.getLong(GroupsQuery._ID);
- final CharSequence title = getGroupTitle(this, childCursor);
+ protected void showRemoveSync(ContextMenu menu, final AccountDisplay account,
+ final GroupDelta child, final int syncMode) {
+ final CharSequence title = child.getTitle(this);
menu.setHeaderTitle(title);
menu.add(R.string.menu_sync_remove).setOnMenuItemClickListener(
new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
- handleRemoveSync(groupId, account, syncMode, title, shouldSyncUngrouped);
+ handleRemoveSync(account, child, syncMode, title);
return true;
}
});
}
- protected void handleRemoveSync(final long groupId, final Account account, final int syncMode,
- CharSequence title, boolean shouldSyncUngrouped) {
- if (syncMode == SYNC_MODE_EVERYTHING && groupId != UNGROUPED_ID && shouldSyncUngrouped) {
+ protected void handleRemoveSync(final AccountDisplay account, final GroupDelta child,
+ final int syncMode, CharSequence title) {
+ final boolean shouldSyncUngrouped = account.mUngrouped.getShouldSync();
+ if (syncMode == SYNC_MODE_EVERYTHING && shouldSyncUngrouped
+ && !child.equals(account.mUngrouped)) {
// Warn before removing this group when it would cause ungrouped to stop syncing
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
final CharSequence removeMessage = this.getString(
@@ -362,96 +742,38 @@
builder.setNegativeButton(android.R.string.cancel, null);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
- // Mark this group to not sync
- setGroupShouldSync(groupId, account, syncMode, false);
+ // Mark both this group and ungrouped to stop syncing
+ account.setShouldSync(account.mUngrouped, false);
+ account.setShouldSync(child, false);
+ mAdapter.notifyDataSetChanged();
}
});
builder.show();
} else {
// Mark this group to not sync
- setGroupShouldSync(groupId, account, syncMode, false);
+ account.setShouldSync(child, false);
+ mAdapter.notifyDataSetChanged();
}
}
- protected void showAddSync(ContextMenu menu, Cursor groupCursor, final Account account,
- final int syncMode) {
+ protected void showAddSync(ContextMenu menu, final AccountDisplay account, final int syncMode) {
menu.setHeaderTitle(R.string.dialog_sync_add);
- // Create single "Ungrouped" item when not synced
- final boolean ungroupedAvailable = groupCursor.getInt(SettingsQuery.SHOULD_SYNC) == 0;
- if (ungroupedAvailable) {
- menu.add(R.string.display_ungrouped).setOnMenuItemClickListener(
- new OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- // Adding specific group for syncing
- setGroupShouldSync(UNGROUPED_ID, account, syncMode, true);
- return true;
- }
- });
- }
-
// Create item for each available, unsynced group
- final Cursor availableGroups = this.managedQuery(Groups.CONTENT_SUMMARY_URI,
- GroupsQuery.PROJECTION, Groups.SHOULD_SYNC + "=0 AND " + Groups.ACCOUNT_NAME
- + "=? AND " + Groups.ACCOUNT_TYPE + "=?", new String[] {
- groupCursor.getString(SettingsQuery.ACCOUNT_NAME),
- groupCursor.getString(SettingsQuery.ACCOUNT_TYPE)
- }, null);
- while (availableGroups.moveToNext()) {
- // Create item this unsynced group
- final long groupId = availableGroups.getLong(GroupsQuery._ID);
- final CharSequence title = getGroupTitle(this, availableGroups);
- menu.add(title).setOnMenuItemClickListener(new OnMenuItemClickListener() {
- public boolean onMenuItemClick(MenuItem item) {
- // Adding specific group for syncing
- setGroupShouldSync(groupId, account, syncMode, true);
- return true;
- }
- });
- }
- }
-
- /**
- * Mark the {@link Groups#SHOULD_SYNC} state of the given group.
- */
- protected void setGroupShouldSync(long groupId, Account account, int syncMode, boolean shouldSync) {
- final ContentResolver resolver = getContentResolver();
- final ContentValues values = new ContentValues();
-
- if (syncMode == SYNC_MODE_UNSUPPORTED) {
- // Ignore changes when source doesn't support syncing
- return;
- }
-
- if (groupId == UNGROUPED_ID) {
- // Updating the overall syncing flag for this account
- values.put(Settings.SHOULD_SYNC, shouldSync ? 1 : 0);
- resolver.update(sDelayedSettings, values, Settings.ACCOUNT_NAME + "=? AND "
- + Settings.ACCOUNT_TYPE + "=?", new String[] {
- account.name, account.type
- });
-
- if (syncMode == SYNC_MODE_EVERYTHING && shouldSync) {
- // If syncing mode is everything, force-enable all children groups
- values.clear();
- values.put(Groups.SHOULD_SYNC, shouldSync ? 1 : 0);
- resolver.update(sDelayedGroups, values, Groups.ACCOUNT_NAME + "=? AND "
- + Groups.ACCOUNT_TYPE + "=?", new String[] {
- account.name, account.type
- });
- }
- } else {
- // Treat as normal group
- values.put(Groups.SHOULD_SYNC, shouldSync ? 1 : 0);
- resolver.update(sDelayedGroups, values, Groups._ID + "=" + groupId, null);
-
- if (syncMode == SYNC_MODE_EVERYTHING && !shouldSync) {
- // Remove "everything" from sync, user has already been warned
- values.clear();
- values.put(Settings.SHOULD_SYNC, shouldSync ? 1 : 0);
- resolver.update(sDelayedSettings, values, Settings.ACCOUNT_NAME + "=? AND "
- + Settings.ACCOUNT_TYPE + "=?", new String[] {
- account.name, account.type
+ for (final GroupDelta child : account.mUnsyncedGroups) {
+ if (!child.getShouldSync()) {
+ final CharSequence title = child.getTitle(this);
+ menu.add(title).setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ // Adding specific group for syncing
+ if (child.mUngrouped && syncMode == SYNC_MODE_EVERYTHING) {
+ account.setShouldSync(true);
+ } else {
+ account.setShouldSync(child, true);
+ }
+ mAdapter.notifyDataSetChanged();
+ return true;
+ }
});
}
}
@@ -460,17 +782,21 @@
/** {@inheritDoc} */
@Override
public void onBackPressed() {
- // TODO: somehow update visibility when user leaves through a different
- // path, never actually pressing the back key
- new UpdateTask(this).execute();
+ doSaveAction();
+ }
+
+ private void doSaveAction() {
+ if (mAdapter == null) return;
+ setDisplayOnlyPhones(mDisplayPhones.isChecked());
+ new UpdateTask(this).execute(mAdapter.mAccounts);
}
/**
- * Background task that uses {@link Contacts#FORCE_STARRED_UPDATE} to force
- * update of {@link Contacts#IN_VISIBLE_GROUP}, showing spinner dialog to
- * user while updating.
+ * Background task that persists changes to {@link Groups#GROUP_VISIBLE},
+ * showing spinner dialog to user while updating.
*/
- public static class UpdateTask extends WeakAsyncTask<Void, Void, Void, Activity> {
+ public static class UpdateTask extends
+ WeakAsyncTask<AccountSet, Void, Void, Activity> {
private WeakReference<ProgressDialog> mProgress;
public UpdateTask(Activity target) {
@@ -482,8 +808,8 @@
protected void onPreExecute(Activity target) {
final Context context = target;
- mProgress = new WeakReference<ProgressDialog>(ProgressDialog.show(target, null,
- target.getText(R.string.savingDisplayGroups)));
+ mProgress = new WeakReference<ProgressDialog>(ProgressDialog.show(context, null,
+ context.getText(R.string.savingDisplayGroups)));
// Before starting this task, start an empty service to protect our
// process from being reclaimed by the system.
@@ -492,16 +818,21 @@
/** {@inheritDoc} */
@Override
- protected Void doInBackground(Activity target, Void... params) {
+ protected Void doInBackground(Activity target, AccountSet... params) {
final Context context = target;
-
final ContentValues values = new ContentValues();
final ContentResolver resolver = context.getContentResolver();
- // Push through an empty update to trigger forced refresh
- final Uri forcedGroups = Groups.CONTENT_URI.buildUpon().appendQueryParameter(
- Contacts.FORCE_STARRED_UPDATE, "1").build();
- resolver.update(forcedGroups, values, null, null);
+ try {
+ // Build changes and persist in transaction
+ final AccountSet set = params[0];
+ final ArrayList<ContentProviderOperation> diff = set.buildDiff();
+ resolver.applyBatch(ContactsContract.AUTHORITY, diff);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Problem saving display groups", e);
+ } catch (OperationApplicationException e) {
+ Log.e(TAG, "Problem saving display groups", e);
+ }
return null;
}
@@ -520,358 +851,4 @@
context.stopService(new Intent(context, EmptyService.class));
}
}
-
-
- /**
- * Return the best title for the {@link Groups} entry at the current
- * {@link Cursor} position.
- */
- protected static CharSequence getGroupTitle(Context context, Cursor cursor) {
- final PackageManager pm = context.getPackageManager();
- if (!cursor.isNull(GroupsQuery.TITLE_RES)) {
- final String packageName = cursor.getString(GroupsQuery.RES_PACKAGE);
- final int titleRes = cursor.getInt(GroupsQuery.TITLE_RES);
- return pm.getText(packageName, titleRes, null);
- } else {
- return cursor.getString(GroupsQuery.TITLE);
- }
- }
-
- /**
- * Special {@link Cursor} that shows zero or one items based on
- * {@link Settings#SHOULD_SYNC} value. This header only supports
- * {@link #SYNC_MODE_UNGROUPED} and {@link #SYNC_MODE_UNSUPPORTED}.
- */
- private static class HeaderCursor extends AbstractCursor {
- private Context mContext;
- private Cursor mCursor;
- private int mPosition;
-
- public HeaderCursor(Context context, Cursor cursor, int position) {
- mContext = context;
- mCursor = cursor;
- mPosition = position;
- }
-
- @Override
- public int getCount() {
- assertParent();
-
- final boolean shouldSync = mCursor.getInt(SettingsQuery.SHOULD_SYNC) != 0;
- return shouldSync ? 1 : 0;
- }
-
- @Override
- public String[] getColumnNames() {
- return GroupsQuery.PROJECTION;
- }
-
- protected void assertParent() {
- mCursor.moveToPosition(mPosition);
- }
-
- @Override
- public String getString(int column) {
- assertParent();
- switch(column) {
- case GroupsQuery.ACCOUNT_NAME:
- return mCursor.getString(SettingsQuery.ACCOUNT_NAME);
- case GroupsQuery.ACCOUNT_TYPE:
- return mCursor.getString(SettingsQuery.ACCOUNT_TYPE);
- case GroupsQuery.TITLE:
- return null;
- case GroupsQuery.RES_PACKAGE:
- return mContext.getPackageName();
- case GroupsQuery.TITLE_RES:
- return Integer.toString(UNGROUPED_ID);
- }
- throw new IllegalArgumentException("Requested column not available as string");
- }
-
- @Override
- public short getShort(int column) {
- throw new IllegalArgumentException("Requested column not available as short");
- }
-
- @Override
- public int getInt(int column) {
- assertParent();
- switch(column) {
- case GroupsQuery._ID:
- return UNGROUPED_ID;
- case GroupsQuery.TITLE_RES:
- return R.string.display_ungrouped;
- case GroupsQuery.GROUP_VISIBLE:
- return mCursor.getInt(SettingsQuery.UNGROUPED_VISIBLE);
-// case GroupsQuery.SUMMARY_COUNT:
-// return mCursor.getInt(SettingsQuery.UNGROUPED_COUNT);
-// case GroupsQuery.SUMMARY_WITH_PHONES:
-// return mCursor.getInt(SettingsQuery.UNGROUPED_WITH_PHONES);
- }
- throw new IllegalArgumentException("Requested column not available as int");
- }
-
- @Override
- public long getLong(int column) {
- return getInt(column);
- }
-
- @Override
- public float getFloat(int column) {
- throw new IllegalArgumentException("Requested column not available as float");
- }
-
- @Override
- public double getDouble(int column) {
- throw new IllegalArgumentException("Requested column not available as double");
- }
-
- @Override
- public boolean isNull(int column) {
- return getString(column) == null;
- }
- }
-
- /**
- * Special {@link Cursor} that shows zero or one items based on
- * {@link Settings#ANY_UNSYNCED} value.
- */
- private static class FooterCursor extends AbstractCursor {
- private Context mContext;
- private Cursor mCursor;
- private int mPosition;
-
- public FooterCursor(Context context, Cursor cursor, int position) {
- mContext = context;
- mCursor = cursor;
- mPosition = position;
- }
-
- @Override
- public int getCount() {
- assertParent();
-
- final boolean anyUnsynced = mCursor.getInt(SettingsQuery.ANY_UNSYNCED) != 0;
- return anyUnsynced ? 1 : 0;
- }
-
- @Override
- public String[] getColumnNames() {
- return GroupsQuery.PROJECTION;
- }
-
- protected void assertParent() {
- mCursor.moveToPosition(mPosition);
- }
-
- @Override
- public String getString(int column) {
- assertParent();
- switch(column) {
- case GroupsQuery.ACCOUNT_NAME:
- return mCursor.getString(SettingsQuery.ACCOUNT_NAME);
- case GroupsQuery.ACCOUNT_TYPE:
- return mCursor.getString(SettingsQuery.ACCOUNT_TYPE);
- case GroupsQuery.TITLE:
- return null;
- case GroupsQuery.RES_PACKAGE:
- return mContext.getPackageName();
- case GroupsQuery.TITLE_RES:
- return Integer.toString(UNSYNCED_ID);
- }
- throw new IllegalArgumentException("Requested column not available as string");
- }
-
- @Override
- public short getShort(int column) {
- throw new IllegalArgumentException("Requested column not available as short");
- }
-
- @Override
- public int getInt(int column) {
- assertParent();
- switch(column) {
- case GroupsQuery._ID:
- return UNSYNCED_ID;
- case GroupsQuery.TITLE_RES:
- return R.string.display_more_groups;
- case GroupsQuery.GROUP_VISIBLE:
- case GroupsQuery.SUMMARY_COUNT:
- case GroupsQuery.SUMMARY_WITH_PHONES:
- return FOOTER_ENTRY;
- }
- throw new IllegalArgumentException("Requested column not available as int");
- }
-
- @Override
- public long getLong(int column) {
- return getInt(column);
- }
-
- @Override
- public float getFloat(int column) {
- throw new IllegalArgumentException("Requested column not available as float");
- }
-
- @Override
- public double getDouble(int column) {
- throw new IllegalArgumentException("Requested column not available as double");
- }
-
- @Override
- public boolean isNull(int column) {
- return getString(column) == null;
- }
- }
-
- /**
- * Adapter that shows all display groups as returned by a {@link Cursor}
- * over {@link Groups#CONTENT_SUMMARY_URI}, along with their current visible
- * status. Splits groups into sections based on {@link Account}.
- */
- private static class DisplayGroupsAdapter extends CursorTreeAdapter {
- private Context mContext;
- private Activity mActivity;
- private LayoutInflater mInflater;
- private Sources mSources;
-
- private boolean mChildWithPhones = false;
-
- public DisplayGroupsAdapter(Cursor cursor, Context context, Activity activity) {
- super(cursor, context, true);
-
- mContext = context;
- mActivity = activity;
- mSources = Sources.getInstance(mContext);
- mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- }
-
- /**
- * In group descriptions, show the number of contacts with phone
- * numbers, in addition to the total contacts.
- */
- public void setChildDescripWithPhones(boolean withPhones) {
- mChildWithPhones = withPhones;
- }
-
- @Override
- protected View newGroupView(Context context, Cursor cursor, boolean isExpanded,
- ViewGroup parent) {
- return mInflater.inflate(R.layout.display_group, parent, false);
- }
-
- @Override
- protected void bindGroupView(View view, Context context, Cursor cursor, boolean isExpanded) {
- final TextView text1 = (TextView)view.findViewById(android.R.id.text1);
- final TextView text2 = (TextView)view.findViewById(android.R.id.text2);
-
- final String accountName = cursor.getString(SettingsQuery.ACCOUNT_NAME);
- final String accountType = cursor.getString(SettingsQuery.ACCOUNT_TYPE);
-
- final ContactsSource source = mSources.getInflatedSource(accountType,
- ContactsSource.LEVEL_SUMMARY);
-
- text1.setText(source.getDisplayLabel(mContext));
- text2.setText(accountName);
- text2.setVisibility(accountName == null ? View.GONE : View.VISIBLE);
- }
-
- @Override
- protected Cursor getChildrenCursor(Cursor groupCursor) {
- final String selection = Groups.ACCOUNT_NAME + "=? AND " + Groups.ACCOUNT_TYPE
- + "=? AND " + Groups.SHOULD_SYNC + "=1";
- final String[] selectionArgs = new String[] {
- groupCursor.getString(SettingsQuery.ACCOUNT_NAME),
- groupCursor.getString(SettingsQuery.ACCOUNT_TYPE)
- };
-
- final int position = groupCursor.getPosition();
- final Cursor ungroupedCursor = new HeaderCursor(mContext, groupCursor, position);
- final Cursor unsyncedCursor = new FooterCursor(mContext, groupCursor, position);
-
- final ContentResolver resolver = mContext.getContentResolver();
- final Cursor groupsCursor = resolver.query(Groups.CONTENT_SUMMARY_URI,
- GroupsQuery.PROJECTION, selection, selectionArgs, null);
- mActivity.startManagingCursor(groupsCursor);
-
- return new MergeCursor(new Cursor[] { ungroupedCursor, groupsCursor, unsyncedCursor });
- }
-
- @Override
- protected View newChildView(Context context, Cursor cursor, boolean isLastChild,
- ViewGroup parent) {
- return mInflater.inflate(R.layout.display_child, parent, false);
- }
-
- @Override
- protected void bindChildView(View view, Context context, Cursor cursor, boolean isLastChild) {
- final TextView text1 = (TextView)view.findViewById(android.R.id.text1);
- final TextView text2 = (TextView)view.findViewById(android.R.id.text2);
- final CheckBox checkbox = (CheckBox)view.findViewById(android.R.id.checkbox);
-
-// final int count = cursor.getInt(GroupsQuery.SUMMARY_COUNT);
-// final int withPhones = cursor.getInt(GroupsQuery.SUMMARY_WITH_PHONES);
- final int membersVisible = cursor.getInt(GroupsQuery.GROUP_VISIBLE);
-
- // Read title, but override with string resource when present
- final CharSequence title = getGroupTitle(mContext, cursor);
-// final CharSequence descrip = mContext.getResources().getQuantityString(
-// mChildWithPhones ? R.plurals.groupDescripPhones : R.plurals.groupDescrip,
-// count, count, withPhones);
-
- text1.setText(title);
-// text2.setText(descrip);
- checkbox.setChecked((membersVisible == 1));
-
- // Hide extra views when recycled as footer
- final boolean footerView = membersVisible == FOOTER_ENTRY;
-// text2.setVisibility(footerView ? View.GONE : View.VISIBLE);
- text2.setVisibility(View.GONE);
- checkbox.setVisibility(footerView ? View.GONE : View.VISIBLE);
- }
- }
-
- private interface SettingsQuery {
- final String[] PROJECTION = new String[] {
- Settings.ACCOUNT_NAME,
- Settings.ACCOUNT_TYPE,
- Settings.SHOULD_SYNC,
- Settings.UNGROUPED_VISIBLE,
- Settings.ANY_UNSYNCED,
-// Settings.UNGROUPED_COUNT,
-// Settings.UNGROUPED_WITH_PHONES,
- };
-
- final int ACCOUNT_NAME = 0;
- final int ACCOUNT_TYPE = 1;
- final int SHOULD_SYNC = 2;
- final int UNGROUPED_VISIBLE = 3;
- final int ANY_UNSYNCED = 4;
-// final int UNGROUPED_COUNT = 5;
-// final int UNGROUPED_WITH_PHONES = 6;
- }
-
- private interface GroupsQuery {
- final String[] PROJECTION = new String[] {
- Groups._ID,
- Groups.TITLE,
- Groups.RES_PACKAGE,
- Groups.TITLE_RES,
- Groups.GROUP_VISIBLE,
- Groups.ACCOUNT_NAME,
- Groups.ACCOUNT_TYPE,
-// Groups.SUMMARY_COUNT,
-// Groups.SUMMARY_WITH_PHONES,
- };
-
- final int _ID = 0;
- final int TITLE = 1;
- final int RES_PACKAGE = 2;
- final int TITLE_RES = 3;
- final int GROUP_VISIBLE = 4;
- final int ACCOUNT_NAME = 5;
- final int ACCOUNT_TYPE = 6;
- final int SUMMARY_COUNT = 7;
- final int SUMMARY_WITH_PHONES = 8;
- }
}
diff --git a/src/com/android/contacts/ui/EditContactActivity.java b/src/com/android/contacts/ui/EditContactActivity.java
index 9b380df..450f4a9 100644
--- a/src/com/android/contacts/ui/EditContactActivity.java
+++ b/src/com/android/contacts/ui/EditContactActivity.java
@@ -97,6 +97,7 @@
private ScrollingTabWidget mTabWidget;
private ContactHeaderWidget mHeader;
+ private TextView mAccountName;
private ContactEditorView mEditor;
@@ -120,10 +121,12 @@
// Header bar is filled later after queries finish
mHeader = (ContactHeaderWidget)this.findViewById(R.id.contact_header_widget);
mHeader.setContactHeaderListener(this);
- mHeader.showStar(true);
+ mHeader.showStar(false);
+ mHeader.enableClickListeners();
mTabWidget = (ScrollingTabWidget)this.findViewById(R.id.tab_widget);
mTabWidget.setTabSelectionListener(this);
+ mAccountName = (TextView)mTabWidget.findViewById(R.id.account_name);
// Build editor and listen for photo requests
mEditor = (ContactEditorView)this.findViewById(android.R.id.tabcontent);
@@ -178,7 +181,7 @@
}
} else if (android.provider.Contacts.AUTHORITY.equals(authority)) {
final long rawContactId = ContentUris.parseId(data);
- selection = RawContacts._ID + "=" + rawContactId;
+ selection = Data.RAW_CONTACT_ID + "=" + rawContactId;
}
target.mQuerySelection = selection;
@@ -393,29 +396,32 @@
if (entity == null) return;
final Sources sources = Sources.getInstance(this);
- final String accountType = entity.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
+ final ValuesDelta values = entity.getValues();
+ final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
+ final String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
final ContactsSource source = sources.getInflatedSource(accountType,
ContactsSource.LEVEL_CONSTRAINTS);
+ mAccountName.setText(getString(R.string.account_name_format,
+ source.getDisplayLabel(this), accountName));
+ mAccountName.setVisibility(View.VISIBLE);
+
// Assign editor state based on entity and source
mEditor.setState(entity, source);
}
/** {@inheritDoc} */
- public void onDisplayNameLongClick(View view) {
+ public void onDisplayNameClick(View view) {
if (!hasValidState()) return;
showAndManageDialog(createNameDialog());
}
/** {@inheritDoc} */
- public void onPhotoLongClick(View view) {
+ public void onPhotoClick(View view) {
if (!hasValidState()) return;
showAndManageDialog(createPhotoDialog());
}
-
-
-
/** {@inheritDoc} */
public void onClick(View view) {
switch (view.getId()) {
@@ -428,7 +434,6 @@
}
}
-
/** {@inheritDoc} */
@Override
public void onBackPressed() {
diff --git a/src/com/android/contacts/ui/FastTrackWindow.java b/src/com/android/contacts/ui/FastTrackWindow.java
index 769b957..25a0167 100644
--- a/src/com/android/contacts/ui/FastTrackWindow.java
+++ b/src/com/android/contacts/ui/FastTrackWindow.java
@@ -495,7 +495,7 @@
// TODO: switch to provider-specific presence dots instead of using
// overall summary dot.
final String name = cursor.getString(SummaryQuery.DISPLAY_NAME);
- final int status = cursor.getInt(SummaryQuery.PRESENCE_STATUS);
+ final int status = cursor.getInt(SummaryQuery.CONTACT_PRESENCE);
final Drawable statusIcon = getPresenceIcon(status);
setHeaderText(R.id.name, name);
@@ -1268,14 +1268,14 @@
final String[] PROJECTION = new String[] {
Contacts.DISPLAY_NAME,
Contacts.PHOTO_ID,
- Contacts.PRESENCE_STATUS,
- Contacts.PRESENCE_CUSTOM_STATUS,
+ Contacts.CONTACT_PRESENCE,
+ Contacts.CONTACT_STATUS,
};
final int DISPLAY_NAME = 0;
final int PHOTO_ID = 1;
- final int PRESENCE_STATUS = 2;
- final int PRESENCE_CUSTOM_STATUS = 3;
+ final int CONTACT_PRESENCE = 2;
+ final int CONTACT_STATUS = 3;
}
private interface SocialQuery {
diff --git a/src/com/android/contacts/ui/widget/ContactEditorView.java b/src/com/android/contacts/ui/widget/ContactEditorView.java
index 35a32cf..cd94e52 100644
--- a/src/com/android/contacts/ui/widget/ContactEditorView.java
+++ b/src/com/android/contacts/ui/widget/ContactEditorView.java
@@ -173,6 +173,8 @@
EntityModifier.ensureKindExists(state, source, Photo.CONTENT_ITEM_TYPE);
mHasPhotoEditor = (source.getKindForMimetype(Photo.CONTENT_ITEM_TYPE) != null);
mPhoto.setVisibility(mHasPhotoEditor ? View.VISIBLE : View.GONE);
+ mPhoto.setEnabled(!source.readOnly);
+ mName.setEnabled(!source.readOnly);
mReadOnly.setVisibility(source.readOnly ? View.VISIBLE : View.GONE);
@@ -185,18 +187,18 @@
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);
+ mName.setValues(kind, primary, state, source.readOnly);
} else if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
// Handle special case editor for photos
final ValuesDelta primary = state.getPrimaryEntry(mimeType);
- mPhoto.setValues(kind, primary, state);
+ mPhoto.setValues(kind, primary, state, source.readOnly);
} else {
// Otherwise use generic section-based editors
if (kind.fieldList == null) continue;
final ViewGroup parent = kind.secondary ? mSecondary : mGeneral;
final KindSectionView section = (KindSectionView)mInflater.inflate(
R.layout.item_kind_section, parent, false);
- section.setState(kind, state);
+ section.setState(kind, state, source.readOnly);
section.setId(kind.weight);
parent.addView(section);
}
diff --git a/src/com/android/contacts/ui/widget/GenericEditorView.java b/src/com/android/contacts/ui/widget/GenericEditorView.java
index 53dd2e0..6387374 100644
--- a/src/com/android/contacts/ui/widget/GenericEditorView.java
+++ b/src/com/android/contacts/ui/widget/GenericEditorView.java
@@ -70,6 +70,7 @@
protected DataKind mKind;
protected ValuesDelta mEntry;
protected EntityDelta mState;
+ protected boolean mReadOnly;
protected boolean mHideOptional = true;
@@ -113,6 +114,16 @@
mDelete.setVisibility(deletable ? View.VISIBLE : View.INVISIBLE);
}
+ public void setEnabled(boolean enabled) {
+ mLabel.setEnabled(enabled);
+ final int count = mFields.getChildCount();
+ for (int pos = 0; pos < count; pos++) {
+ final View v = mFields.getChildAt(pos);
+ v.setEnabled(enabled);
+ }
+ mMore.setEnabled(enabled);
+ }
+
/**
* Build the current label state based on selected {@link EditType} and
* possible custom label string.
@@ -144,17 +155,20 @@
}
private void rebuildValues() {
- setValues(mKind, mEntry, mState);
+ setValues(mKind, mEntry, mState, mReadOnly);
}
/**
* Prepare this editor using the given {@link DataKind} for defining
* structure and {@link ValuesDelta} describing the content to edit.
*/
- public void setValues(DataKind kind, ValuesDelta entry, EntityDelta state) {
+ public void setValues(DataKind kind, ValuesDelta entry, EntityDelta state, boolean readOnly) {
mKind = kind;
mEntry = entry;
mState = state;
+ mReadOnly = readOnly;
+
+ final boolean enabled = !readOnly;
if (!entry.isVisible()) {
// Hide ourselves entirely if deleted
@@ -167,6 +181,7 @@
// Display label selector if multiple types available
final boolean hasTypes = EntityModifier.hasEditTypes(kind);
mLabel.setVisibility(hasTypes ? View.VISIBLE : View.GONE);
+ mLabel.setEnabled(enabled);
if (hasTypes) {
mType = EntityModifier.getCurrentType(entry, kind);
rebuildLabel();
@@ -207,6 +222,7 @@
final boolean couldHide = (TextUtils.isEmpty(value) && field.optional);
final boolean willHide = (mHideOptional && couldHide);
fieldView.setVisibility(willHide ? View.GONE : View.VISIBLE);
+ fieldView.setEnabled(enabled);
hidePossible = hidePossible || couldHide;
mFields.addView(fieldView);
@@ -214,6 +230,7 @@
// When hiding fields, place expandable
mMore.setVisibility(hidePossible ? View.VISIBLE : View.GONE);
+ mMore.setEnabled(enabled);
}
/**
diff --git a/src/com/android/contacts/ui/widget/KindSectionView.java b/src/com/android/contacts/ui/widget/KindSectionView.java
index 5a63992..b52cfd0 100644
--- a/src/com/android/contacts/ui/widget/KindSectionView.java
+++ b/src/com/android/contacts/ui/widget/KindSectionView.java
@@ -50,6 +50,7 @@
private DataKind mKind;
private EntityDelta mState;
+ private boolean mReadOnly;
public KindSectionView(Context context) {
super(context);
@@ -87,9 +88,10 @@
// Ignore requests
}
- public void setState(DataKind kind, EntityDelta state) {
+ public void setState(DataKind kind, EntityDelta state, boolean readOnly) {
mKind = kind;
mState = state;
+ mReadOnly = readOnly;
// TODO: handle resources from remote packages
mTitle.setText(kind.titleRes);
@@ -114,7 +116,7 @@
final GenericEditorView editor = (GenericEditorView)mInflater.inflate(
R.layout.item_generic_editor, mEditors, false);
- editor.setValues(mKind, entry, mState);
+ editor.setValues(mKind, entry, mState, mReadOnly);
editor.setEditorListener(this);
editor.setId(entry.getViewId());
mEditors.addView(editor);
@@ -129,7 +131,8 @@
protected void updateAddEnabled() {
// Set enabled state on the "add" view
final boolean canInsert = EntityModifier.canInsert(mState, mKind);
- mAdd.setEnabled(canInsert);
+ final boolean isEnabled = !mReadOnly && canInsert;
+ mAdd.setEnabled(isEnabled);
}
/** {@inheritDoc} */
diff --git a/src/com/android/contacts/ui/widget/PhotoEditorView.java b/src/com/android/contacts/ui/widget/PhotoEditorView.java
index cde314d..184b907 100644
--- a/src/com/android/contacts/ui/widget/PhotoEditorView.java
+++ b/src/com/android/contacts/ui/widget/PhotoEditorView.java
@@ -74,7 +74,7 @@
}
/** {@inheritDoc} */
- public void setValues(DataKind kind, ValuesDelta values, EntityDelta state) {
+ public void setValues(DataKind kind, ValuesDelta values, EntityDelta state, boolean readOnly) {
mEntry = values;
if (values != null) {
// Try decoding photo if actual entry
@@ -85,6 +85,7 @@
setScaleType(ImageView.ScaleType.CENTER_CROP);
setImageBitmap(photo);
+ setEnabled(!readOnly);
mHasSetPhoto = true;
} else {
resetDefault();
diff --git a/src/com/android/contacts/util/AccountSelectionUtil.java b/src/com/android/contacts/util/AccountSelectionUtil.java
new file mode 100644
index 0000000..cf83581
--- /dev/null
+++ b/src/com/android/contacts/util/AccountSelectionUtil.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.util;
+
+import com.android.contacts.ImportVCardActivity;
+import com.android.contacts.R;
+import com.android.contacts.model.ContactsSource;
+import com.android.contacts.model.GoogleSource;
+import com.android.contacts.model.Sources;
+
+import android.accounts.Account;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.util.Log;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+
+import java.util.List;
+
+/**
+ * Utility class for selectiong an Account for importing contact(s)
+ */
+public class AccountSelectionUtil {
+ // TODO: maybe useful for EditContactActivity.java...
+ private static final String LOG_TAG = "AccountSelectionUtil";
+
+ private static class AccountSelectedListener
+ implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
+
+ final private Context mContext;
+ final private List<Account> mAccountList;
+ final private int mResId;
+
+ public AccountSelectedListener(Context context, List<Account> accountList, int resId) {
+ if (accountList == null || accountList.size() == 0) {
+ Log.e(LOG_TAG, "The size of Account list is 0.");
+ }
+ mContext = context;
+ mAccountList = accountList;
+ mResId = resId;
+ }
+
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ doImport(mContext, mResId, mAccountList.get(which));
+ }
+
+ public void onCancel(DialogInterface dialog) {
+ dialog.dismiss();
+ }
+ }
+
+ public static Dialog getSelectAccountDialog(Context context, int resId) {
+ return getSelectAccountDialog(context, resId, null);
+ }
+
+ public static Dialog getSelectAccountDialog(Context context, int resId,
+ DialogInterface.OnCancelListener onCancelListener) {
+ final Sources sources = Sources.getInstance(context);
+ final List<Account> writableAccountList = sources.getAccounts(true);
+
+ // Assume accountList.size() > 1
+
+ // Wrap our context to inflate list items using correct theme
+ final Context dialogContext = new ContextThemeWrapper(
+ context, android.R.style.Theme_Light);
+ final LayoutInflater dialogInflater = (LayoutInflater)dialogContext
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ final ArrayAdapter<Account> accountAdapter =
+ new ArrayAdapter<Account>(context, android.R.layout.simple_list_item_2,
+ writableAccountList) {
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = dialogInflater.inflate(
+ android.R.layout.simple_list_item_2,
+ parent, false);
+ }
+
+ // TODO: show icon along with title
+ final TextView text1 =
+ (TextView)convertView.findViewById(android.R.id.text1);
+ final TextView text2 =
+ (TextView)convertView.findViewById(android.R.id.text2);
+
+ final Account account = this.getItem(position);
+ final ContactsSource source =
+ sources.getInflatedSource(account.type,
+ ContactsSource.LEVEL_SUMMARY);
+ final Context context = getContext();
+
+ text1.setText(account.name);
+ text2.setText(source.getDisplayLabel(context));
+
+ return convertView;
+ }
+ };
+
+ AccountSelectedListener accountSelectedListener =
+ new AccountSelectedListener(context, writableAccountList, resId);
+ return new AlertDialog.Builder(context)
+ .setTitle(R.string.dialog_new_contact_account)
+ .setSingleChoiceItems(accountAdapter, 0, accountSelectedListener)
+ .setOnCancelListener(accountSelectedListener)
+ .create();
+ }
+
+ public static void doImport(Context context, int resId, Account account) {
+ switch (resId) {
+ case R.string.import_from_sim: {
+ doImportFromSim(context, account);
+ break;
+ }
+ case R.string.import_from_sdcard: {
+ doImportFromSdCard(context, account);
+ break;
+ }
+ }
+ }
+
+ public static void doImportFromSim(Context context, Account account) {
+ if (account != null) {
+ GoogleSource.createMyContactsIfNotExist(account, context);
+ }
+
+ Intent importIntent = new Intent(Intent.ACTION_VIEW);
+ importIntent.setType("vnd.android.cursor.item/sim-contact");
+ if (account != null) {
+ importIntent.putExtra("account_name", account.name);
+ importIntent.putExtra("account_type", account.type);
+ }
+ importIntent.setClassName("com.android.phone", "com.android.phone.SimContacts");
+ context.startActivity(importIntent);
+ }
+
+ public static void doImportFromSdCard(Context context, Account account) {
+ if (account != null) {
+ GoogleSource.createMyContactsIfNotExist(account, context);
+ }
+
+ Intent importIntent = new Intent(context, ImportVCardActivity.class);
+ if (account != null) {
+ importIntent.putExtra("account_name", account.name);
+ importIntent.putExtra("account_type", account.type);
+ }
+ context.startActivity(importIntent);
+ }
+}
diff --git a/tests/src/com/android/contacts/RecentCallsListActivityTests.java b/tests/src/com/android/contacts/RecentCallsListActivityTests.java
new file mode 100644
index 0000000..2cdd8d7
--- /dev/null
+++ b/tests/src/com/android/contacts/RecentCallsListActivityTests.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts;
+
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.provider.CallLog.Calls;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
+import android.view.View;
+import android.widget.FrameLayout;
+import com.android.contacts.RecentCallsListActivity;
+import com.android.internal.telephony.CallerInfo;
+import java.util.Date;
+import java.util.Formatter;
+import java.util.HashMap;
+import java.util.Random;
+
+/**
+ * Tests for the contact call list activity.
+ *
+ * Running all tests:
+ *
+ * runtest contacts
+ * or
+ * adb shell am instrument \
+ * -w com.android.contacts.tests/android.test.InstrumentationTestRunner
+ */
+
+public class RecentCallsListActivityTests
+ extends ActivityInstrumentationTestCase2<RecentCallsListActivity> {
+ static private final String TAG = "RecentCallsListActivityTests";
+ static private final String[] CALL_LOG_PROJECTION = new String[] {
+ Calls._ID,
+ Calls.NUMBER,
+ Calls.DATE,
+ Calls.DURATION,
+ Calls.TYPE,
+ Calls.CACHED_NAME,
+ Calls.CACHED_NUMBER_TYPE,
+ Calls.CACHED_NUMBER_LABEL
+ };
+ static private final int RAND_DURATION = -1;
+ static private final long NOW = -1L;
+
+ // We get the call list activity and assign is a frame to build
+ // its list. mAdapter is an inner class of
+ // RecentCallsListActivity to build the rows (view) in the call
+ // list. We reuse it with our own in-mem DB.
+ private RecentCallsListActivity mActivity;
+ private FrameLayout mParentView;
+ private RecentCallsListActivity.RecentCallsAdapter mAdapter;
+ private String mVoicemail;
+
+ // In memory array to hold the rows corresponding to the 'calls' table.
+ private MatrixCursor mCursor;
+ private int mIndex; // Of the next row.
+
+ private Random mRnd;
+
+ // References to the icons bitmaps used to build the list are stored in a
+ // map mIcons. The keys to retrieve the icons are:
+ // Calls.INCOMING_TYPE, Calls.OUTGOING_TYPE and Calls.MISSED_TYPE.
+ private HashMap<Integer, Bitmap> mCallTypeIcons;
+
+ // An item in the call list. All the methods performing checks use it.
+ private RecentCallsListActivity.RecentCallsListItemViews mItem;
+ // The list of views representing the data in the DB. View are in
+ // reverse order compare to the DB.
+ private View[] mList;
+
+ public RecentCallsListActivityTests() {
+ super("com.android.contacts", RecentCallsListActivity.class);
+ mIndex = 1;
+ mRnd = new Random();
+ }
+
+ @Override
+ public void setUp() {
+ mActivity = (RecentCallsListActivity) getActivity();
+ mVoicemail = mActivity.mVoiceMailNumber;
+ mAdapter = mActivity.mAdapter;
+ mParentView = new FrameLayout(mActivity);
+ mCursor = new MatrixCursor(CALL_LOG_PROJECTION);
+ buildIconMap();
+ }
+
+ /**
+ * Checks that the call icon is not visible for private and
+ * unknown numbers.
+ * Use 2 passes, one where new views are created and one where
+ * half of the total views are updated and the other half created.
+ */
+ @MediumTest
+ public void testCallViewIsNotVisibleForPrivateAndUnknownNumbers() {
+ final int SIZE = 100;
+ mList = new View[SIZE];
+
+ // Insert the first batch of entries.
+ mCursor.moveToFirst();
+ insertRandomEntries(SIZE / 2);
+ int startOfSecondBatch = mCursor.getPosition();
+
+ buildViewListFromDb();
+ checkCallStatus();
+
+ // Append the rest of the entries. We keep the first set of
+ // views around so they get updated and not built from
+ // scratch, this exposes some bugs that are not there when the
+ // call log is launched for the 1st time but show up when the
+ // call log gets updated afterwards.
+ mCursor.move(startOfSecondBatch);
+ insertRandomEntries(SIZE / 2);
+
+ buildViewListFromDb();
+ checkCallStatus();
+ }
+
+ //
+ // HELPERS to check conditions on the DB/views
+ //
+ /**
+ * Check the date of the current list item.
+ * @param date That should be present in the call log list
+ * item. Only NOW is supported.
+ */
+ private void checkDate(long date) {
+ if (NOW == date) {
+ assertEquals("0 mins ago", mItem.dateView.getText());
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Checks the right icon is used to represent the call type
+ * (missed, incoming, outgoing.) in the current item.
+ */
+ private void checkCallType(int type) {
+ Bitmap icon = ((BitmapDrawable) mItem.iconView.getDrawable()).getBitmap();
+ assertEquals(mCallTypeIcons.get(type), icon);
+ }
+
+ /**
+ * Go over all the views in the list and check that the Call
+ * icon's visibility matches the nature of the number.
+ */
+ private void checkCallStatus() {
+ for (int i = 0; i < mList.length; i++) {
+ if (null == mList[i]) {
+ break;
+ }
+ mItem = (RecentCallsListActivity.RecentCallsListItemViews) mList[i].getTag();
+
+ // callView tag is the phone number.
+ String number = (String) mItem.callView.getTag();
+
+ if (CallerInfo.PRIVATE_NUMBER.equals(number) ||
+ CallerInfo.UNKNOWN_NUMBER.equals(number)) {
+ assertFalse(View.VISIBLE == mItem.callView.getVisibility());
+ } else {
+ assertEquals(View.VISIBLE, mItem.callView.getVisibility());
+ }
+ }
+ }
+
+
+ //
+ // HELPERS to setup the tests.
+ //
+
+ /**
+ * Get the Bitmap from the icons in the contacts package.
+ */
+ private Bitmap getBitmap(String resName) {
+ Resources r = mActivity.getResources();
+ int resid = r.getIdentifier(resName, "drawable", "com.android.contacts");
+ BitmapDrawable d = (BitmapDrawable) r.getDrawable(resid);
+ assertNotNull(d);
+ return d.getBitmap();
+ }
+
+ /**
+ * Fetch all the icons we need in tests from the contacts app and store them in a map.
+ */
+ private void buildIconMap() {
+ mCallTypeIcons = new HashMap<Integer, Bitmap>(3);
+
+ mCallTypeIcons.put(Calls.INCOMING_TYPE, getBitmap("ic_call_log_list_incoming_call"));
+ mCallTypeIcons.put(Calls.MISSED_TYPE, getBitmap("ic_call_log_list_missed_call"));
+ mCallTypeIcons.put(Calls.OUTGOING_TYPE, getBitmap("ic_call_log_list_outgoing_call"));
+ }
+
+ //
+ // HELPERS to build/update the call entries (views) from the DB.
+ //
+
+ /**
+ * Read the DB and foreach call either update the existing view if
+ * one exists already otherwise create one.
+ * The list is build from a DESC view of the DB (last inserted entry is first).
+ */
+ private void buildViewListFromDb() {
+ int i = 0;
+ mCursor.moveToLast();
+ while(!mCursor.isBeforeFirst()) {
+ if (null == mList[i]) {
+ mList[i] = mAdapter.newView(mActivity, mCursor, mParentView);
+ }
+ mAdapter.bindView(mList[i], mActivity, mCursor);
+ mCursor.moveToPrevious();
+ i++;
+ }
+ }
+
+ //
+ // HELPERS to insert numbers in the call log DB.
+ //
+
+ /**
+ * Insert a certain number of random numbers in the DB. Makes sure
+ * there is at least one private and one unknown number in the DB.
+ * @param num Of entries to be inserted.
+ */
+ private void insertRandomEntries(int num) {
+ if (num < 10) {
+ throw new IllegalArgumentException("num should be >= 10");
+ }
+ boolean privateOrUnknownOrVm[];
+ privateOrUnknownOrVm = insertRandomRange(0, num - 2);
+
+ if (privateOrUnknownOrVm[0] && privateOrUnknownOrVm[1]) {
+ insertRandomRange(num - 2, num);
+ } else {
+ insertPrivate(NOW, RAND_DURATION);
+ insertUnknown(NOW, RAND_DURATION);
+ }
+ }
+
+ /**
+ * Insert a new call entry in the test DB.
+ * @param number The phone number. For unknown and private numbers,
+ * use CallerInfo.UNKNOWN_NUMBER or CallerInfo.PRIVATE_NUMBER.
+ * @param date In millisec since epoch. Use NOW to use the current time.
+ * @param duration In seconds of the call. Use RAND_DURATION to pick a random one.
+ * @param type Eigher Call.OUTGOING_TYPE or Call.INCOMING_TYPE or Call.MISSED_TYPE.
+ */
+ private void insert(String number, long date, int duration, int type) {
+ MatrixCursor.RowBuilder row = mCursor.newRow();
+ row.add(mIndex);
+ mIndex ++;
+ row.add(number);
+ if (NOW == date) {
+ row.add(new Date().getTime());
+ }
+ if (duration < 0) {
+ duration = mRnd.nextInt(10 * 60); // 0 - 10 minutes random.
+ }
+ row.add(duration); // duration
+ if (mVoicemail.equals(number)) {
+ assertEquals(Calls.OUTGOING_TYPE, type);
+ }
+ row.add(type); // type
+ row.add(""); // cached name
+ row.add(0); // cached number type
+ row.add(""); // cached number label
+ }
+
+ /**
+ * Insert a new private call entry in the test DB.
+ * @param date In millisec since epoch. Use NOW to use the current time.
+ * @param duration In seconds of the call. Use RAND_DURATION to pick a random one.
+ */
+ private void insertPrivate(long date, int duration) {
+ insert(CallerInfo.PRIVATE_NUMBER, date, duration, Calls.INCOMING_TYPE);
+ }
+
+ /**
+ * Insert a new unknown call entry in the test DB.
+ * @param date In millisec since epoch. Use NOW to use the current time.
+ * @param duration In seconds of the call. Use RAND_DURATION to pick a random one.
+ */
+ private void insertUnknown(long date, int duration) {
+ insert(CallerInfo.UNKNOWN_NUMBER, date, duration, Calls.INCOMING_TYPE);
+ }
+
+ /**
+ * Insert a new voicemail call entry in the test DB.
+ * @param date In millisec since epoch. Use NOW to use the current time.
+ * @param duration In seconds of the call. Use RAND_DURATION to pick a random one.
+ */
+ private void insertVoicemail(long date, int duration) {
+ insert(mVoicemail, date, duration, Calls.OUTGOING_TYPE);
+ }
+
+ /**
+ * Insert a range [start, end) of random numbers in the DB. For
+ * each row, there is a 1/10 probability that the number will be
+ * marked as PRIVATE or UNKNOWN or VOICEMAIL. For regular numbers, a number is
+ * inserted, its last 4 digits will be the number of the iteration
+ * in the range.
+ * @param start Of the range.
+ * @param end Of the range (excluded).
+ * @return An array with 2 booleans [0 = private number, 1 =
+ * unknown number, 2 = voicemail] to indicate if at least one
+ * private or unknown or voicemail number has been inserted. Since
+ * the numbers are random some tests may want to enforce the
+ * insertion of such numbers.
+ */
+ // TODO: Should insert numbers with contact entries too.
+ private boolean[] insertRandomRange(int start, int end) {
+ boolean[] privateOrUnknownOrVm = new boolean[] {false, false, false};
+
+ for (int i = start; i < end; i++ ) {
+ int type = mRnd.nextInt(10);
+
+ if (0 == type) {
+ insertPrivate(NOW, RAND_DURATION);
+ privateOrUnknownOrVm[0] = true;
+ } else if (1 == type) {
+ insertUnknown(NOW, RAND_DURATION);
+ privateOrUnknownOrVm[1] = true;
+ } else if (2 == type) {
+ insertVoicemail(NOW, RAND_DURATION);
+ privateOrUnknownOrVm[2] = true;
+ } else {
+ int inout = mRnd.nextBoolean() ? Calls.OUTGOING_TYPE : Calls.INCOMING_TYPE;
+ String number = new Formatter().format("1800123%04d", i).toString();
+ insert(number, NOW, RAND_DURATION, inout);
+ }
+ }
+ return privateOrUnknownOrVm;
+ }
+}