Merge "Allow a sync adapter to provide an OPEN action for a group"
diff --git a/res/anim/aizy_preview_popup_enter.xml b/res/anim/aizy_preview_popup_enter.xml
deleted file mode 100644
index 194a3a3..0000000
--- a/res/anim/aizy_preview_popup_enter.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2010, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:interpolator="@android:anim/accelerate_interpolator">
-	<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
-            android:duration="@android:integer/config_shortAnimTime" />
-</set>
diff --git a/res/anim/aizy_preview_popup_exit.xml b/res/anim/aizy_preview_popup_exit.xml
deleted file mode 100644
index ed5cda8..0000000
--- a/res/anim/aizy_preview_popup_exit.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2010, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:interpolator="@android:anim/accelerate_interpolator">
-	<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
-            android:duration="@android:integer/config_longAnimTime" />
-</set>
diff --git a/res/anim/footer_appear.xml b/res/anim/footer_appear.xml
deleted file mode 100644
index 941454a..0000000
--- a/res/anim/footer_appear.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<translate xmlns:android="http://schemas.android.com/apk/res/android"
-    android:fromYDelta="+10%p"
-    android:toYDelta="0"
-    android:duration="300" />
\ No newline at end of file
diff --git a/res/drawable-hdpi/bg_status_contact_widget.9.png b/res/drawable-hdpi/bg_status_contact_widget.9.png
index 5615057..a2853c0 100644
--- a/res/drawable-hdpi/bg_status_contact_widget.9.png
+++ b/res/drawable-hdpi/bg_status_contact_widget.9.png
Binary files differ
diff --git a/res/drawable-hdpi/btn_dial_action_left_disable.9.png b/res/drawable-hdpi/btn_dial_action_left_disable.9.png
deleted file mode 100644
index f693c41..0000000
--- a/res/drawable-hdpi/btn_dial_action_left_disable.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/btn_dial_action_left_disable_focused.9.png b/res/drawable-hdpi/btn_dial_action_left_disable_focused.9.png
deleted file mode 100644
index 67080f7..0000000
--- a/res/drawable-hdpi/btn_dial_action_left_disable_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/btn_dial_action_left_normal.9.png b/res/drawable-hdpi/btn_dial_action_left_normal.9.png
deleted file mode 100644
index 2f17d86..0000000
--- a/res/drawable-hdpi/btn_dial_action_left_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/btn_dial_action_left_pressed.9.png b/res/drawable-hdpi/btn_dial_action_left_pressed.9.png
deleted file mode 100644
index 54f34ed..0000000
--- a/res/drawable-hdpi/btn_dial_action_left_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/btn_dial_action_left_selected.9.png b/res/drawable-hdpi/btn_dial_action_left_selected.9.png
deleted file mode 100644
index a00bca4..0000000
--- a/res/drawable-hdpi/btn_dial_action_left_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/btn_dial_normal.9.png b/res/drawable-hdpi/btn_dial_normal.9.png
deleted file mode 100644
index aba4382..0000000
--- a/res/drawable-hdpi/btn_dial_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/contacts_widget_preview.png b/res/drawable-hdpi/contacts_widget_preview.png
index 89b2f45..4cc51ad 100644
--- a/res/drawable-hdpi/contacts_widget_preview.png
+++ b/res/drawable-hdpi/contacts_widget_preview.png
Binary files differ
diff --git a/res/drawable-hdpi/dial_num_0_wht.png b/res/drawable-hdpi/dial_num_0_wht.png
index 172457b..b7672e0 100644
--- a/res/drawable-hdpi/dial_num_0_wht.png
+++ b/res/drawable-hdpi/dial_num_0_wht.png
Binary files differ
diff --git a/res/drawable-hdpi/dial_num_1_wht.png b/res/drawable-hdpi/dial_num_1_wht.png
index b05227b..5381f03 100644
--- a/res/drawable-hdpi/dial_num_1_wht.png
+++ b/res/drawable-hdpi/dial_num_1_wht.png
Binary files differ
diff --git a/res/drawable-hdpi/dial_num_2_wht.png b/res/drawable-hdpi/dial_num_2_wht.png
index 59b798f..903f036 100644
--- a/res/drawable-hdpi/dial_num_2_wht.png
+++ b/res/drawable-hdpi/dial_num_2_wht.png
Binary files differ
diff --git a/res/drawable-hdpi/dial_num_3_wht.png b/res/drawable-hdpi/dial_num_3_wht.png
index 4291341..e840f86 100644
--- a/res/drawable-hdpi/dial_num_3_wht.png
+++ b/res/drawable-hdpi/dial_num_3_wht.png
Binary files differ
diff --git a/res/drawable-hdpi/dial_num_4_wht.png b/res/drawable-hdpi/dial_num_4_wht.png
index 9901ba0..45a238a 100644
--- a/res/drawable-hdpi/dial_num_4_wht.png
+++ b/res/drawable-hdpi/dial_num_4_wht.png
Binary files differ
diff --git a/res/drawable-hdpi/dial_num_5_wht.png b/res/drawable-hdpi/dial_num_5_wht.png
index 905b2db..e563242 100644
--- a/res/drawable-hdpi/dial_num_5_wht.png
+++ b/res/drawable-hdpi/dial_num_5_wht.png
Binary files differ
diff --git a/res/drawable-hdpi/dial_num_6_wht.png b/res/drawable-hdpi/dial_num_6_wht.png
index 08e3a6c..e916968 100644
--- a/res/drawable-hdpi/dial_num_6_wht.png
+++ b/res/drawable-hdpi/dial_num_6_wht.png
Binary files differ
diff --git a/res/drawable-hdpi/dial_num_7_wht.png b/res/drawable-hdpi/dial_num_7_wht.png
index 3ba7aa6..090366a 100644
--- a/res/drawable-hdpi/dial_num_7_wht.png
+++ b/res/drawable-hdpi/dial_num_7_wht.png
Binary files differ
diff --git a/res/drawable-hdpi/dial_num_8_wht.png b/res/drawable-hdpi/dial_num_8_wht.png
index 5e670ed..f898450 100644
--- a/res/drawable-hdpi/dial_num_8_wht.png
+++ b/res/drawable-hdpi/dial_num_8_wht.png
Binary files differ
diff --git a/res/drawable-hdpi/dial_num_9_wht.png b/res/drawable-hdpi/dial_num_9_wht.png
index 5a8fc9a..999457c 100644
--- a/res/drawable-hdpi/dial_num_9_wht.png
+++ b/res/drawable-hdpi/dial_num_9_wht.png
Binary files differ
diff --git a/res/drawable-hdpi/dial_num_pound_wht.png b/res/drawable-hdpi/dial_num_pound_wht.png
index 2ddc21d..44aa276 100644
--- a/res/drawable-hdpi/dial_num_pound_wht.png
+++ b/res/drawable-hdpi/dial_num_pound_wht.png
Binary files differ
diff --git a/res/drawable-hdpi/dial_num_star_wht.png b/res/drawable-hdpi/dial_num_star_wht.png
index 832031f..edd6e06 100644
--- a/res/drawable-hdpi/dial_num_star_wht.png
+++ b/res/drawable-hdpi/dial_num_star_wht.png
Binary files differ
diff --git a/res/drawable-hdpi/frame_thumbnail_contact_widget_focused_holo.png b/res/drawable-hdpi/frame_thumbnail_contact_widget_focused_holo.png
index e2a9fe0..352d4d9 100644
--- a/res/drawable-hdpi/frame_thumbnail_contact_widget_focused_holo.png
+++ b/res/drawable-hdpi/frame_thumbnail_contact_widget_focused_holo.png
Binary files differ
diff --git a/res/drawable-hdpi/frame_thumbnail_contact_widget_holo.png b/res/drawable-hdpi/frame_thumbnail_contact_widget_holo.png
new file mode 100644
index 0000000..d4223e1
--- /dev/null
+++ b/res/drawable-hdpi/frame_thumbnail_contact_widget_holo.png
Binary files differ
diff --git a/res/drawable-hdpi/frame_thumbnail_contact_widget_pressed_holo.png b/res/drawable-hdpi/frame_thumbnail_contact_widget_pressed_holo.png
index 1f5b5f9..5f0966f 100644
--- a/res/drawable-hdpi/frame_thumbnail_contact_widget_pressed_holo.png
+++ b/res/drawable-hdpi/frame_thumbnail_contact_widget_pressed_holo.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_call_incoming_holo_dark.png b/res/drawable-hdpi/ic_call_incoming_holo_dark.png
new file mode 100644
index 0000000..df6f190
--- /dev/null
+++ b/res/drawable-hdpi/ic_call_incoming_holo_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_call_log_list_incoming_call.png b/res/drawable-hdpi/ic_call_log_list_incoming_call.png
deleted file mode 100644
index 624a0c5..0000000
--- a/res/drawable-hdpi/ic_call_log_list_incoming_call.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_call_log_list_missed_call.png b/res/drawable-hdpi/ic_call_log_list_missed_call.png
deleted file mode 100644
index bd572cd..0000000
--- a/res/drawable-hdpi/ic_call_log_list_missed_call.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_call_log_list_outgoing_call.png b/res/drawable-hdpi/ic_call_log_list_outgoing_call.png
deleted file mode 100644
index 1a93a78..0000000
--- a/res/drawable-hdpi/ic_call_log_list_outgoing_call.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_call_log_list_voicemail.png b/res/drawable-hdpi/ic_call_log_list_voicemail.png
deleted file mode 100644
index 0c2a6f4..0000000
--- a/res/drawable-hdpi/ic_call_log_list_voicemail.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_call_missed_holo_dark.png b/res/drawable-hdpi/ic_call_missed_holo_dark.png
new file mode 100644
index 0000000..a6bdb8d
--- /dev/null
+++ b/res/drawable-hdpi/ic_call_missed_holo_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_call_outgoing_holo_dark.png b/res/drawable-hdpi/ic_call_outgoing_holo_dark.png
new file mode 100644
index 0000000..657655d
--- /dev/null
+++ b/res/drawable-hdpi/ic_call_outgoing_holo_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_call_voicemail_holo_dark.png b/res/drawable-hdpi/ic_call_voicemail_holo_dark.png
new file mode 100644
index 0000000..734050d
--- /dev/null
+++ b/res/drawable-hdpi/ic_call_voicemail_holo_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_dial_action_voice_mail.png b/res/drawable-hdpi/ic_dial_action_voice_mail.png
deleted file mode 100644
index 6607bb8..0000000
--- a/res/drawable-hdpi/ic_dial_action_voice_mail.png
+++ /dev/null
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..3e1ea44
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_contacts.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_folder_live_contacts.png b/res/drawable-hdpi/ic_launcher_folder_live_contacts.png
new file mode 100644
index 0000000..84babe2
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_folder_live_contacts.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_folder_live_contacts_phone.png b/res/drawable-hdpi/ic_launcher_folder_live_contacts_phone.png
new file mode 100644
index 0000000..004e849
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_folder_live_contacts_phone.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_folder_live_contacts_starred.png b/res/drawable-hdpi/ic_launcher_folder_live_contacts_starred.png
new file mode 100644
index 0000000..73b4fa5
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_folder_live_contacts_starred.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_shortcut_contact.png b/res/drawable-hdpi/ic_launcher_shortcut_contact.png
new file mode 100644
index 0000000..d86b264
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_shortcut_contact.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_shortcut_directdial.png b/res/drawable-hdpi/ic_launcher_shortcut_directdial.png
new file mode 100644
index 0000000..e7ff8f8
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_shortcut_directdial.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_shortcut_directmessage.png b/res/drawable-hdpi/ic_launcher_shortcut_directmessage.png
new file mode 100644
index 0000000..5170a75
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_shortcut_directmessage.png
Binary files differ
diff --git a/res/drawable-hdpi/list_item_divider_holo.9.png b/res/drawable-hdpi/list_item_divider_holo.9.png
deleted file mode 100644
index f5130d5..0000000
--- a/res/drawable-hdpi/list_item_divider_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/list_title_holo.9.png b/res/drawable-hdpi/list_title_holo.9.png
index ebdd4e3..ae93717 100644
--- a/res/drawable-hdpi/list_title_holo.9.png
+++ b/res/drawable-hdpi/list_title_holo.9.png
Binary files differ
diff --git a/res/drawable-hdpi/panel_content.9.png b/res/drawable-hdpi/panel_content.9.png
index 4a9b90a..8c412ed 100644
--- a/res/drawable-hdpi/panel_content.9.png
+++ b/res/drawable-hdpi/panel_content.9.png
Binary files differ
diff --git a/res/drawable-hdpi/quickactions_icon_activated.9.png b/res/drawable-hdpi/quickactions_icon_activated.9.png
index b9ccc80..dd68562 100644
--- a/res/drawable-hdpi/quickactions_icon_activated.9.png
+++ b/res/drawable-hdpi/quickactions_icon_activated.9.png
Binary files differ
diff --git a/res/drawable-hdpi/section_header_holo.9.png b/res/drawable-hdpi/section_header_holo.9.png
deleted file mode 100644
index de12d0e..0000000
--- a/res/drawable-hdpi/section_header_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/statusbox_landscape_holo_light.9.png b/res/drawable-hdpi/statusbox_landscape_holo_light.9.png
index 9fa578c..12001e6 100644
--- a/res/drawable-hdpi/statusbox_landscape_holo_light.9.png
+++ b/res/drawable-hdpi/statusbox_landscape_holo_light.9.png
Binary files differ
diff --git a/res/drawable-hdpi/statusbox_portrait_holo_light.9.png b/res/drawable-hdpi/statusbox_portrait_holo_light.9.png
index 614bc59..6dcb8c0 100644
--- a/res/drawable-hdpi/statusbox_portrait_holo_light.9.png
+++ b/res/drawable-hdpi/statusbox_portrait_holo_light.9.png
Binary files differ
diff --git a/res/drawable-hdpi/title_bar_medium.9.png b/res/drawable-hdpi/title_bar_medium.9.png
deleted file mode 100644
index 311a54a..0000000
--- a/res/drawable-hdpi/title_bar_medium.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/title_bar_shadow.9.png b/res/drawable-hdpi/title_bar_shadow.9.png
deleted file mode 100755
index a5e458a..0000000
--- a/res/drawable-hdpi/title_bar_shadow.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/btn_dial_action_left_disable.9.png b/res/drawable-mdpi/btn_dial_action_left_disable.9.png
deleted file mode 100644
index 8eb45c8..0000000
--- a/res/drawable-mdpi/btn_dial_action_left_disable.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/btn_dial_action_left_disable_focused.9.png b/res/drawable-mdpi/btn_dial_action_left_disable_focused.9.png
deleted file mode 100644
index b9951ef..0000000
--- a/res/drawable-mdpi/btn_dial_action_left_disable_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/btn_dial_action_left_normal.9.png b/res/drawable-mdpi/btn_dial_action_left_normal.9.png
deleted file mode 100644
index 5f091f2..0000000
--- a/res/drawable-mdpi/btn_dial_action_left_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/btn_dial_action_left_pressed.9.png b/res/drawable-mdpi/btn_dial_action_left_pressed.9.png
deleted file mode 100644
index c84bbfe..0000000
--- a/res/drawable-mdpi/btn_dial_action_left_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/btn_dial_action_left_selected.9.png b/res/drawable-mdpi/btn_dial_action_left_selected.9.png
deleted file mode 100644
index 1960abc..0000000
--- a/res/drawable-mdpi/btn_dial_action_left_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/btn_dial_normal.9.png b/res/drawable-mdpi/btn_dial_normal.9.png
deleted file mode 100644
index 68dccee..0000000
--- a/res/drawable-mdpi/btn_dial_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/dial_background_texture.png b/res/drawable-mdpi/dial_background_texture.png
index ea27fd2..de6b72a 100644
--- a/res/drawable-mdpi/dial_background_texture.png
+++ b/res/drawable-mdpi/dial_background_texture.png
Binary files differ
diff --git a/res/drawable-mdpi/dial_num_0_wht.png b/res/drawable-mdpi/dial_num_0_wht.png
index f37be81..eff8c59 100644
--- a/res/drawable-mdpi/dial_num_0_wht.png
+++ b/res/drawable-mdpi/dial_num_0_wht.png
Binary files differ
diff --git a/res/drawable-mdpi/dial_num_1_wht.png b/res/drawable-mdpi/dial_num_1_wht.png
index 3e11285..fe79a16 100644
--- a/res/drawable-mdpi/dial_num_1_wht.png
+++ b/res/drawable-mdpi/dial_num_1_wht.png
Binary files differ
diff --git a/res/drawable-mdpi/dial_num_2_wht.png b/res/drawable-mdpi/dial_num_2_wht.png
index bfcf48f..759ed42 100644
--- a/res/drawable-mdpi/dial_num_2_wht.png
+++ b/res/drawable-mdpi/dial_num_2_wht.png
Binary files differ
diff --git a/res/drawable-mdpi/dial_num_3_wht.png b/res/drawable-mdpi/dial_num_3_wht.png
index c37fdcf..5cddb1d 100644
--- a/res/drawable-mdpi/dial_num_3_wht.png
+++ b/res/drawable-mdpi/dial_num_3_wht.png
Binary files differ
diff --git a/res/drawable-mdpi/dial_num_4_wht.png b/res/drawable-mdpi/dial_num_4_wht.png
index d4144ee..10878ec 100644
--- a/res/drawable-mdpi/dial_num_4_wht.png
+++ b/res/drawable-mdpi/dial_num_4_wht.png
Binary files differ
diff --git a/res/drawable-mdpi/dial_num_5_wht.png b/res/drawable-mdpi/dial_num_5_wht.png
index 3984429..514744b 100644
--- a/res/drawable-mdpi/dial_num_5_wht.png
+++ b/res/drawable-mdpi/dial_num_5_wht.png
Binary files differ
diff --git a/res/drawable-mdpi/dial_num_6_wht.png b/res/drawable-mdpi/dial_num_6_wht.png
index dfd95f9..8877c64 100644
--- a/res/drawable-mdpi/dial_num_6_wht.png
+++ b/res/drawable-mdpi/dial_num_6_wht.png
Binary files differ
diff --git a/res/drawable-mdpi/dial_num_7_wht.png b/res/drawable-mdpi/dial_num_7_wht.png
index 9bf517f..0e76d7d 100644
--- a/res/drawable-mdpi/dial_num_7_wht.png
+++ b/res/drawable-mdpi/dial_num_7_wht.png
Binary files differ
diff --git a/res/drawable-mdpi/dial_num_8_wht.png b/res/drawable-mdpi/dial_num_8_wht.png
index 0077cc5..62ea5fd 100644
--- a/res/drawable-mdpi/dial_num_8_wht.png
+++ b/res/drawable-mdpi/dial_num_8_wht.png
Binary files differ
diff --git a/res/drawable-mdpi/dial_num_9_wht.png b/res/drawable-mdpi/dial_num_9_wht.png
index 0c4e43f..53194a4 100644
--- a/res/drawable-mdpi/dial_num_9_wht.png
+++ b/res/drawable-mdpi/dial_num_9_wht.png
Binary files differ
diff --git a/res/drawable-mdpi/dial_num_pound_wht.png b/res/drawable-mdpi/dial_num_pound_wht.png
index e2c65ad..9dfd878 100644
--- a/res/drawable-mdpi/dial_num_pound_wht.png
+++ b/res/drawable-mdpi/dial_num_pound_wht.png
Binary files differ
diff --git a/res/drawable-mdpi/dial_num_star_wht.png b/res/drawable-mdpi/dial_num_star_wht.png
index 1c9a09a..cbb21da 100644
--- a/res/drawable-mdpi/dial_num_star_wht.png
+++ b/res/drawable-mdpi/dial_num_star_wht.png
Binary files differ
diff --git a/res/drawable-mdpi/frame_thumbnail_contact_widget_holo.png b/res/drawable-mdpi/frame_thumbnail_contact_widget_holo.png
new file mode 100644
index 0000000..a62834c
--- /dev/null
+++ b/res/drawable-mdpi/frame_thumbnail_contact_widget_holo.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_call_incoming_holo_dark.png b/res/drawable-mdpi/ic_call_incoming_holo_dark.png
new file mode 100644
index 0000000..055f9c6
--- /dev/null
+++ b/res/drawable-mdpi/ic_call_incoming_holo_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_call_log_list_incoming_call.png b/res/drawable-mdpi/ic_call_log_list_incoming_call.png
deleted file mode 100644
index 77be776..0000000
--- a/res/drawable-mdpi/ic_call_log_list_incoming_call.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_call_log_list_missed_call.png b/res/drawable-mdpi/ic_call_log_list_missed_call.png
deleted file mode 100644
index 66c8d85..0000000
--- a/res/drawable-mdpi/ic_call_log_list_missed_call.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_call_log_list_outgoing_call.png b/res/drawable-mdpi/ic_call_log_list_outgoing_call.png
deleted file mode 100644
index a7f85b2..0000000
--- a/res/drawable-mdpi/ic_call_log_list_outgoing_call.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_call_log_list_voicemail.png b/res/drawable-mdpi/ic_call_log_list_voicemail.png
deleted file mode 100644
index 6aec9ed..0000000
--- a/res/drawable-mdpi/ic_call_log_list_voicemail.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_call_missed_holo_dark.png b/res/drawable-mdpi/ic_call_missed_holo_dark.png
new file mode 100644
index 0000000..ab098ee
--- /dev/null
+++ b/res/drawable-mdpi/ic_call_missed_holo_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_call_outgoing_holo_dark.png b/res/drawable-mdpi/ic_call_outgoing_holo_dark.png
new file mode 100644
index 0000000..aaf2b87
--- /dev/null
+++ b/res/drawable-mdpi/ic_call_outgoing_holo_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_call_voicemail_holo_dark.png b/res/drawable-mdpi/ic_call_voicemail_holo_dark.png
new file mode 100644
index 0000000..bb566bb
--- /dev/null
+++ b/res/drawable-mdpi/ic_call_voicemail_holo_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_dial_action_voice_mail.png b/res/drawable-mdpi/ic_dial_action_voice_mail.png
deleted file mode 100644
index cb07d1a..0000000
--- a/res/drawable-mdpi/ic_dial_action_voice_mail.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_contacts.png b/res/drawable-mdpi/ic_launcher_contacts.png
new file mode 100644
index 0000000..618630f
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_contacts.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_folder_live_contacts.png b/res/drawable-mdpi/ic_launcher_folder_live_contacts.png
new file mode 100644
index 0000000..d49cc7b
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_folder_live_contacts.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_folder_live_contacts_phone.png b/res/drawable-mdpi/ic_launcher_folder_live_contacts_phone.png
new file mode 100644
index 0000000..0127f84
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_folder_live_contacts_phone.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_folder_live_contacts_starred.png b/res/drawable-mdpi/ic_launcher_folder_live_contacts_starred.png
new file mode 100644
index 0000000..8d56b31
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_folder_live_contacts_starred.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_shortcut_contact.png b/res/drawable-mdpi/ic_launcher_shortcut_contact.png
new file mode 100644
index 0000000..20d359d
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_shortcut_contact.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_shortcut_directdial.png b/res/drawable-mdpi/ic_launcher_shortcut_directdial.png
new file mode 100644
index 0000000..7081c08
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_shortcut_directdial.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_shortcut_directmessage.png b/res/drawable-mdpi/ic_launcher_shortcut_directmessage.png
new file mode 100644
index 0000000..374c7c4
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_shortcut_directmessage.png
Binary files differ
diff --git a/res/drawable-mdpi/list_item_divider_holo.9.png b/res/drawable-mdpi/list_item_divider_holo.9.png
deleted file mode 100644
index f5130d5..0000000
--- a/res/drawable-mdpi/list_item_divider_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/list_title_holo.9.png b/res/drawable-mdpi/list_title_holo.9.png
index e866452..64bd691 100644
--- a/res/drawable-mdpi/list_title_holo.9.png
+++ b/res/drawable-mdpi/list_title_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/panel_content.9.png b/res/drawable-mdpi/panel_content.9.png
index 1d30d5f..12604ad 100644
--- a/res/drawable-mdpi/panel_content.9.png
+++ b/res/drawable-mdpi/panel_content.9.png
Binary files differ
diff --git a/res/drawable-mdpi/quickactions_icon_activated.9.png b/res/drawable-mdpi/quickactions_icon_activated.9.png
index 777c988..00479b8 100644
--- a/res/drawable-mdpi/quickactions_icon_activated.9.png
+++ b/res/drawable-mdpi/quickactions_icon_activated.9.png
Binary files differ
diff --git a/res/drawable-mdpi/section_header_holo.9.png b/res/drawable-mdpi/section_header_holo.9.png
deleted file mode 100644
index de12d0e..0000000
--- a/res/drawable-mdpi/section_header_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/statusbox_attribute_holo.9.png b/res/drawable-mdpi/statusbox_attribute_holo.9.png
index b124392..bc5e10f 100644
--- a/res/drawable-mdpi/statusbox_attribute_holo.9.png
+++ b/res/drawable-mdpi/statusbox_attribute_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/statusbox_landscape_holo_light.9.png b/res/drawable-mdpi/statusbox_landscape_holo_light.9.png
index 49546e5..e274c84 100644
--- a/res/drawable-mdpi/statusbox_landscape_holo_light.9.png
+++ b/res/drawable-mdpi/statusbox_landscape_holo_light.9.png
Binary files differ
diff --git a/res/drawable-mdpi/statusbox_portrait_holo_light.9.png b/res/drawable-mdpi/statusbox_portrait_holo_light.9.png
index 902e559..803b866 100644
--- a/res/drawable-mdpi/statusbox_portrait_holo_light.9.png
+++ b/res/drawable-mdpi/statusbox_portrait_holo_light.9.png
Binary files differ
diff --git a/res/drawable-mdpi/title_bar_medium.9.png b/res/drawable-mdpi/title_bar_medium.9.png
deleted file mode 100644
index 2d41d02..0000000
--- a/res/drawable-mdpi/title_bar_medium.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/title_bar_shadow.9.png b/res/drawable-mdpi/title_bar_shadow.9.png
deleted file mode 100644
index 0872366..0000000
--- a/res/drawable-mdpi/title_bar_shadow.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/aggregation_suggestions_bg.9.png b/res/drawable-xhdpi/aggregation_suggestions_bg.9.png
index d3be1d6..816cc0b 100644
--- a/res/drawable-xhdpi/aggregation_suggestions_bg.9.png
+++ b/res/drawable-xhdpi/aggregation_suggestions_bg.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/aggregation_suggestions_bg_light_holo.9.png b/res/drawable-xhdpi/aggregation_suggestions_bg_light_holo.9.png
index 14e1386..94ae50a 100644
--- a/res/drawable-xhdpi/aggregation_suggestions_bg_light_holo.9.png
+++ b/res/drawable-xhdpi/aggregation_suggestions_bg_light_holo.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/bg_blk_search_contact.9.png b/res/drawable-xhdpi/bg_blk_search_contact.9.png
index 691a89c..fc3a05e 100644
--- a/res/drawable-xhdpi/bg_blk_search_contact.9.png
+++ b/res/drawable-xhdpi/bg_blk_search_contact.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/bg_status_contact_widget.9.png b/res/drawable-xhdpi/bg_status_contact_widget.9.png
index c735ce3..db34bf4 100644
--- a/res/drawable-xhdpi/bg_status_contact_widget.9.png
+++ b/res/drawable-xhdpi/bg_status_contact_widget.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_action_left_disable.9.png b/res/drawable-xhdpi/btn_dial_action_left_disable.9.png
deleted file mode 100644
index e6dd9a2..0000000
--- a/res/drawable-xhdpi/btn_dial_action_left_disable.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_action_left_disable_focused.9.png b/res/drawable-xhdpi/btn_dial_action_left_disable_focused.9.png
deleted file mode 100644
index c369c17..0000000
--- a/res/drawable-xhdpi/btn_dial_action_left_disable_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_action_left_normal.9.png b/res/drawable-xhdpi/btn_dial_action_left_normal.9.png
deleted file mode 100644
index cdc0d1f..0000000
--- a/res/drawable-xhdpi/btn_dial_action_left_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_action_left_pressed.9.png b/res/drawable-xhdpi/btn_dial_action_left_pressed.9.png
deleted file mode 100644
index 63af3aa..0000000
--- a/res/drawable-xhdpi/btn_dial_action_left_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_action_left_selected.9.png b/res/drawable-xhdpi/btn_dial_action_left_selected.9.png
deleted file mode 100644
index 05ecf0c..0000000
--- a/res/drawable-xhdpi/btn_dial_action_left_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_action_middle_disable.9.png b/res/drawable-xhdpi/btn_dial_action_middle_disable.9.png
index baa74b1..6da4265 100644
--- a/res/drawable-xhdpi/btn_dial_action_middle_disable.9.png
+++ b/res/drawable-xhdpi/btn_dial_action_middle_disable.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_action_middle_disable_focused.9.png b/res/drawable-xhdpi/btn_dial_action_middle_disable_focused.9.png
index 4519af8..cddf893 100644
--- a/res/drawable-xhdpi/btn_dial_action_middle_disable_focused.9.png
+++ b/res/drawable-xhdpi/btn_dial_action_middle_disable_focused.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_action_middle_normal.9.png b/res/drawable-xhdpi/btn_dial_action_middle_normal.9.png
index 87a1eb6..dc39b98 100644
--- a/res/drawable-xhdpi/btn_dial_action_middle_normal.9.png
+++ b/res/drawable-xhdpi/btn_dial_action_middle_normal.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_action_middle_pressed.9.png b/res/drawable-xhdpi/btn_dial_action_middle_pressed.9.png
index f4ba914..f092867 100644
--- a/res/drawable-xhdpi/btn_dial_action_middle_pressed.9.png
+++ b/res/drawable-xhdpi/btn_dial_action_middle_pressed.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_action_middle_selected.9.png b/res/drawable-xhdpi/btn_dial_action_middle_selected.9.png
index bcd55d1..9577eda 100644
--- a/res/drawable-xhdpi/btn_dial_action_middle_selected.9.png
+++ b/res/drawable-xhdpi/btn_dial_action_middle_selected.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_action_right_disable.9.png b/res/drawable-xhdpi/btn_dial_action_right_disable.9.png
index 96da3e5..fdcd395 100644
--- a/res/drawable-xhdpi/btn_dial_action_right_disable.9.png
+++ b/res/drawable-xhdpi/btn_dial_action_right_disable.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_action_right_disable_focused.9.png b/res/drawable-xhdpi/btn_dial_action_right_disable_focused.9.png
index a91cade..9f4eeb0 100644
--- a/res/drawable-xhdpi/btn_dial_action_right_disable_focused.9.png
+++ b/res/drawable-xhdpi/btn_dial_action_right_disable_focused.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_action_right_normal.9.png b/res/drawable-xhdpi/btn_dial_action_right_normal.9.png
index 5373a47..c6f7e09 100644
--- a/res/drawable-xhdpi/btn_dial_action_right_normal.9.png
+++ b/res/drawable-xhdpi/btn_dial_action_right_normal.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_action_right_pressed.9.png b/res/drawable-xhdpi/btn_dial_action_right_pressed.9.png
index cf1bd27..bf99581 100644
--- a/res/drawable-xhdpi/btn_dial_action_right_pressed.9.png
+++ b/res/drawable-xhdpi/btn_dial_action_right_pressed.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_action_right_selected.9.png b/res/drawable-xhdpi/btn_dial_action_right_selected.9.png
index be86501..5c06f99 100644
--- a/res/drawable-xhdpi/btn_dial_action_right_selected.9.png
+++ b/res/drawable-xhdpi/btn_dial_action_right_selected.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_normal.9.png b/res/drawable-xhdpi/btn_dial_normal.9.png
deleted file mode 100644
index 766470e..0000000
--- a/res/drawable-xhdpi/btn_dial_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_selected.9.png b/res/drawable-xhdpi/btn_dial_selected.9.png
index f436288..1e2fe56 100644
--- a/res/drawable-xhdpi/btn_dial_selected.9.png
+++ b/res/drawable-xhdpi/btn_dial_selected.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_textfield_activated.9.png b/res/drawable-xhdpi/btn_dial_textfield_activated.9.png
index 3602fa8..9c5e4f4 100644
--- a/res/drawable-xhdpi/btn_dial_textfield_activated.9.png
+++ b/res/drawable-xhdpi/btn_dial_textfield_activated.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_textfield_normal.9.png b/res/drawable-xhdpi/btn_dial_textfield_normal.9.png
index cbe790e..9903624 100644
--- a/res/drawable-xhdpi/btn_dial_textfield_normal.9.png
+++ b/res/drawable-xhdpi/btn_dial_textfield_normal.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_textfield_pressed.9.png b/res/drawable-xhdpi/btn_dial_textfield_pressed.9.png
index 17f76b0..00e2e7e 100644
--- a/res/drawable-xhdpi/btn_dial_textfield_pressed.9.png
+++ b/res/drawable-xhdpi/btn_dial_textfield_pressed.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_dial_textfield_selected.9.png b/res/drawable-xhdpi/btn_dial_textfield_selected.9.png
index 25526c0..bf2e27f 100644
--- a/res/drawable-xhdpi/btn_dial_textfield_selected.9.png
+++ b/res/drawable-xhdpi/btn_dial_textfield_selected.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/dial_indicator.png b/res/drawable-xhdpi/dial_indicator.png
deleted file mode 100644
index 384d9c2..0000000
--- a/res/drawable-xhdpi/dial_indicator.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/dial_num_0_wht.png b/res/drawable-xhdpi/dial_num_0_wht.png
index 08042b3..16b2935 100644
--- a/res/drawable-xhdpi/dial_num_0_wht.png
+++ b/res/drawable-xhdpi/dial_num_0_wht.png
Binary files differ
diff --git a/res/drawable-xhdpi/dial_num_1_wht.png b/res/drawable-xhdpi/dial_num_1_wht.png
index 2bf0bc0..28295ee 100644
--- a/res/drawable-xhdpi/dial_num_1_wht.png
+++ b/res/drawable-xhdpi/dial_num_1_wht.png
Binary files differ
diff --git a/res/drawable-xhdpi/dial_num_2_wht.png b/res/drawable-xhdpi/dial_num_2_wht.png
index 8a096f1..ecc8568 100644
--- a/res/drawable-xhdpi/dial_num_2_wht.png
+++ b/res/drawable-xhdpi/dial_num_2_wht.png
Binary files differ
diff --git a/res/drawable-xhdpi/dial_num_3_wht.png b/res/drawable-xhdpi/dial_num_3_wht.png
index 73536dc..1872936 100644
--- a/res/drawable-xhdpi/dial_num_3_wht.png
+++ b/res/drawable-xhdpi/dial_num_3_wht.png
Binary files differ
diff --git a/res/drawable-xhdpi/dial_num_4_wht.png b/res/drawable-xhdpi/dial_num_4_wht.png
index a8ce584..cde2e4c 100644
--- a/res/drawable-xhdpi/dial_num_4_wht.png
+++ b/res/drawable-xhdpi/dial_num_4_wht.png
Binary files differ
diff --git a/res/drawable-xhdpi/dial_num_5_wht.png b/res/drawable-xhdpi/dial_num_5_wht.png
index acb1351..0b94669 100644
--- a/res/drawable-xhdpi/dial_num_5_wht.png
+++ b/res/drawable-xhdpi/dial_num_5_wht.png
Binary files differ
diff --git a/res/drawable-xhdpi/dial_num_6_wht.png b/res/drawable-xhdpi/dial_num_6_wht.png
index 4926653..aff27dd 100644
--- a/res/drawable-xhdpi/dial_num_6_wht.png
+++ b/res/drawable-xhdpi/dial_num_6_wht.png
Binary files differ
diff --git a/res/drawable-xhdpi/dial_num_7_wht.png b/res/drawable-xhdpi/dial_num_7_wht.png
index 1c6c1c2..77da19d 100644
--- a/res/drawable-xhdpi/dial_num_7_wht.png
+++ b/res/drawable-xhdpi/dial_num_7_wht.png
Binary files differ
diff --git a/res/drawable-xhdpi/dial_num_8_wht.png b/res/drawable-xhdpi/dial_num_8_wht.png
index b2a4546..e450e62 100644
--- a/res/drawable-xhdpi/dial_num_8_wht.png
+++ b/res/drawable-xhdpi/dial_num_8_wht.png
Binary files differ
diff --git a/res/drawable-xhdpi/dial_num_9_wht.png b/res/drawable-xhdpi/dial_num_9_wht.png
index c266e8b..0c993e5 100644
--- a/res/drawable-xhdpi/dial_num_9_wht.png
+++ b/res/drawable-xhdpi/dial_num_9_wht.png
Binary files differ
diff --git a/res/drawable-xhdpi/dial_num_pound_wht.png b/res/drawable-xhdpi/dial_num_pound_wht.png
index 19376f0..3be13ae 100644
--- a/res/drawable-xhdpi/dial_num_pound_wht.png
+++ b/res/drawable-xhdpi/dial_num_pound_wht.png
Binary files differ
diff --git a/res/drawable-xhdpi/dial_num_star_wht.png b/res/drawable-xhdpi/dial_num_star_wht.png
index 35ec837..9e699ab 100644
--- a/res/drawable-xhdpi/dial_num_star_wht.png
+++ b/res/drawable-xhdpi/dial_num_star_wht.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_ab_back_holo_dark.png b/res/drawable-xhdpi/ic_ab_back_holo_dark.png
deleted file mode 100644
index 737f7d5..0000000
--- a/res/drawable-xhdpi/ic_ab_back_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_ab_dialer_holo_dark.png b/res/drawable-xhdpi/ic_ab_dialer_holo_dark.png
deleted file mode 100644
index 0aa9b86..0000000
--- a/res/drawable-xhdpi/ic_ab_dialer_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_ab_favourites_holo_dark.png b/res/drawable-xhdpi/ic_ab_favourites_holo_dark.png
deleted file mode 100644
index ac0d685..0000000
--- a/res/drawable-xhdpi/ic_ab_favourites_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_ab_history_holo_dark.png b/res/drawable-xhdpi/ic_ab_history_holo_dark.png
deleted file mode 100644
index d54e421..0000000
--- a/res/drawable-xhdpi/ic_ab_history_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_ab_search_holo_dark.png b/res/drawable-xhdpi/ic_ab_search_holo_dark.png
deleted file mode 100644
index b4db2d3..0000000
--- a/res/drawable-xhdpi/ic_ab_search_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_add_contact_holo_dark.png b/res/drawable-xhdpi/ic_add_contact_holo_dark.png
deleted file mode 100644
index 862652e..0000000
--- a/res/drawable-xhdpi/ic_add_contact_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_bluetooth_holo_dark.png b/res/drawable-xhdpi/ic_bluetooth_holo_dark.png
deleted file mode 100644
index c213595..0000000
--- a/res/drawable-xhdpi/ic_bluetooth_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_call_log_list_incoming_call.png b/res/drawable-xhdpi/ic_call_log_list_incoming_call.png
deleted file mode 100644
index 31be214..0000000
--- a/res/drawable-xhdpi/ic_call_log_list_incoming_call.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_call_log_list_missed_call.png b/res/drawable-xhdpi/ic_call_log_list_missed_call.png
deleted file mode 100644
index b00e68a..0000000
--- a/res/drawable-xhdpi/ic_call_log_list_missed_call.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_call_log_list_outgoing_call.png b/res/drawable-xhdpi/ic_call_log_list_outgoing_call.png
deleted file mode 100644
index 6a19a96..0000000
--- a/res/drawable-xhdpi/ic_call_log_list_outgoing_call.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_contact_list_picture.png b/res/drawable-xhdpi/ic_contact_list_picture.png
deleted file mode 100644
index 181005b..0000000
--- a/res/drawable-xhdpi/ic_contact_list_picture.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_contacts_holo_dark.png b/res/drawable-xhdpi/ic_contacts_holo_dark.png
deleted file mode 100644
index eb82880..0000000
--- a/res/drawable-xhdpi/ic_contacts_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_default_number.png b/res/drawable-xhdpi/ic_default_number.png
deleted file mode 100644
index 972788d..0000000
--- a/res/drawable-xhdpi/ic_default_number.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_dial_action_voice_mail.png b/res/drawable-xhdpi/ic_dial_action_voice_mail.png
deleted file mode 100644
index 8cad4d6..0000000
--- a/res/drawable-xhdpi/ic_dial_action_voice_mail.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_dialpad_holo_dark.png b/res/drawable-xhdpi/ic_dialpad_holo_dark.png
deleted file mode 100644
index c53ef55..0000000
--- a/res/drawable-xhdpi/ic_dialpad_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_fav_quickcontact_holo_dark.png b/res/drawable-xhdpi/ic_fav_quickcontact_holo_dark.png
deleted file mode 100644
index 2fe0804..0000000
--- a/res/drawable-xhdpi/ic_fav_quickcontact_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_hold_pause_holo_dark.png b/res/drawable-xhdpi/ic_hold_pause_holo_dark.png
deleted file mode 100644
index c5c5974..0000000
--- a/res/drawable-xhdpi/ic_hold_pause_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_incall_switch_holo_dark.png b/res/drawable-xhdpi/ic_incall_switch_holo_dark.png
deleted file mode 100644
index d772306..0000000
--- a/res/drawable-xhdpi/ic_incall_switch_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_manage_holo_dark.png b/res/drawable-xhdpi/ic_manage_holo_dark.png
deleted file mode 100644
index 8cfba5e..0000000
--- a/res/drawable-xhdpi/ic_manage_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_add_group_holo_light.png b/res/drawable-xhdpi/ic_menu_add_group_holo_light.png
deleted file mode 100644
index 4e4665a..0000000
--- a/res/drawable-xhdpi/ic_menu_add_group_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_help_holo_light.png b/res/drawable-xhdpi/ic_menu_help_holo_light.png
deleted file mode 100644
index d1dcf17..0000000
--- a/res/drawable-xhdpi/ic_menu_help_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_more_holo_light.png b/res/drawable-xhdpi/ic_menu_more_holo_light.png
deleted file mode 100644
index 5817ea8..0000000
--- a/res/drawable-xhdpi/ic_menu_more_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_moreoverflow_normal_holo_light.png b/res/drawable-xhdpi/ic_menu_moreoverflow_normal_holo_light.png
deleted file mode 100644
index 141c712..0000000
--- a/res/drawable-xhdpi/ic_menu_moreoverflow_normal_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_sound_holo_dark.png b/res/drawable-xhdpi/ic_sound_holo_dark.png
deleted file mode 100644
index da5e9f6..0000000
--- a/res/drawable-xhdpi/ic_sound_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_text_holo_dark.png b/res/drawable-xhdpi/ic_text_holo_dark.png
deleted file mode 100644
index 74d20e7..0000000
--- a/res/drawable-xhdpi/ic_text_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/list_background_holo.9.png b/res/drawable-xhdpi/list_background_holo.9.png
index de090c8..adba6a8 100644
--- a/res/drawable-xhdpi/list_background_holo.9.png
+++ b/res/drawable-xhdpi/list_background_holo.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/list_item_divider_holo.9.png b/res/drawable-xhdpi/list_item_divider_holo.9.png
deleted file mode 100644
index 9fdfc95..0000000
--- a/res/drawable-xhdpi/list_item_divider_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/list_title_holo.9.png b/res/drawable-xhdpi/list_title_holo.9.png
index 0f3421c..f4f00ca 100644
--- a/res/drawable-xhdpi/list_title_holo.9.png
+++ b/res/drawable-xhdpi/list_title_holo.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/panel_message.9.png b/res/drawable-xhdpi/panel_message.9.png
index ddef3cf..ce3c06d 100644
--- a/res/drawable-xhdpi/panel_message.9.png
+++ b/res/drawable-xhdpi/panel_message.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/photo_frame_widget_holo_light.9.png b/res/drawable-xhdpi/photo_frame_widget_holo_light.9.png
deleted file mode 100644
index 9f21a87..0000000
--- a/res/drawable-xhdpi/photo_frame_widget_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/quickactions_icon_activated.9.png b/res/drawable-xhdpi/quickactions_icon_activated.9.png
index c24607a..b3aaf7d 100644
--- a/res/drawable-xhdpi/quickactions_icon_activated.9.png
+++ b/res/drawable-xhdpi/quickactions_icon_activated.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/quickcontacts_selected_holo.9.png b/res/drawable-xhdpi/quickcontacts_selected_holo.9.png
deleted file mode 100644
index 081233f..0000000
--- a/res/drawable-xhdpi/quickcontacts_selected_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/section_header.9.png b/res/drawable-xhdpi/section_header.9.png
index f4ae934..5026ea6 100644
--- a/res/drawable-xhdpi/section_header.9.png
+++ b/res/drawable-xhdpi/section_header.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/sym_action_email.png b/res/drawable-xhdpi/sym_action_email.png
deleted file mode 100644
index 4acedd4..0000000
--- a/res/drawable-xhdpi/sym_action_email.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/sym_action_map.png b/res/drawable-xhdpi/sym_action_map.png
deleted file mode 100644
index 87e71ae..0000000
--- a/res/drawable-xhdpi/sym_action_map.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/tab_focused.9.png b/res/drawable-xhdpi/tab_focused.9.png
index 1ef66d9..b9aba3e 100644
--- a/res/drawable-xhdpi/tab_focused.9.png
+++ b/res/drawable-xhdpi/tab_focused.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/tab_focused_bottom.9.png b/res/drawable-xhdpi/tab_focused_bottom.9.png
index a30fcb9..d404f0b 100644
--- a/res/drawable-xhdpi/tab_focused_bottom.9.png
+++ b/res/drawable-xhdpi/tab_focused_bottom.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/tab_pressed.9.png b/res/drawable-xhdpi/tab_pressed.9.png
index 0d752fc..4a26f77 100644
--- a/res/drawable-xhdpi/tab_pressed.9.png
+++ b/res/drawable-xhdpi/tab_pressed.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/tab_pressed_bottom.9.png b/res/drawable-xhdpi/tab_pressed_bottom.9.png
index d1a4427..a7e1668 100644
--- a/res/drawable-xhdpi/tab_pressed_bottom.9.png
+++ b/res/drawable-xhdpi/tab_pressed_bottom.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/tab_selected.9.png b/res/drawable-xhdpi/tab_selected.9.png
index c732f0d..045a9c7 100644
--- a/res/drawable-xhdpi/tab_selected.9.png
+++ b/res/drawable-xhdpi/tab_selected.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/tab_selected_bottom.9.png b/res/drawable-xhdpi/tab_selected_bottom.9.png
index d708d55..64ff016 100644
--- a/res/drawable-xhdpi/tab_selected_bottom.9.png
+++ b/res/drawable-xhdpi/tab_selected_bottom.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/tab_unselected.9.png b/res/drawable-xhdpi/tab_unselected.9.png
index a650f69..c11a765 100644
--- a/res/drawable-xhdpi/tab_unselected.9.png
+++ b/res/drawable-xhdpi/tab_unselected.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/title_bar_medium.9.png b/res/drawable-xhdpi/title_bar_medium.9.png
deleted file mode 100644
index 2b296ea..0000000
--- a/res/drawable-xhdpi/title_bar_medium.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/title_bar_shadow.9.png b/res/drawable-xhdpi/title_bar_shadow.9.png
deleted file mode 100644
index 310ac75..0000000
--- a/res/drawable-xhdpi/title_bar_shadow.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/divider_vertical_dark.9.png b/res/drawable-xlarge-nodpi/divider_vertical_dark.9.png
new file mode 100644
index 0000000..38b794b
--- /dev/null
+++ b/res/drawable-xlarge-nodpi/divider_vertical_dark.9.png
Binary files differ
diff --git a/res/drawable/btn_dial_action.xml b/res/drawable/btn_dial_action.xml
deleted file mode 100644
index 9ffb31b..0000000
--- a/res/drawable/btn_dial_action.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- Background resource for dial button for the various 12 key dialers. -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <!-- Disabled views -->
-    <item android:state_focused="true" android:state_enabled="false"
-        android:drawable="@drawable/btn_dial_action_middle_disable_focused" />
-    <item android:state_enabled="false"
-        android:drawable="@drawable/btn_dial_action_middle_disable" />
-
-    <!-- Enabled views -->
-    <item android:state_pressed="true" android:state_enabled="true"
-        android:drawable="@drawable/btn_dial_action_middle_pressed" />
-    <item android:state_focused="true" android:state_enabled="true"
-        android:drawable="@drawable/btn_dial_action_middle_selected" />
-    <item android:state_enabled="true"
-        android:drawable="@drawable/btn_dial_action_middle_normal" />
-</selector>
diff --git a/res/drawable/btn_dial_delete.xml b/res/drawable/btn_dial_delete.xml
deleted file mode 100644
index b8c672d..0000000
--- a/res/drawable/btn_dial_delete.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- Background resource for backspace button for the various 12 key dialers. -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <!-- Disabled views -->
-    <item android:state_focused="true" android:state_enabled="false"
-        android:drawable="@drawable/btn_dial_action_right_disable_focused" />
-    <item android:state_enabled="false"
-        android:drawable="@drawable/btn_dial_action_right_disable" />
-
-    <!-- Enabled views -->
-    <item android:state_pressed="true" android:state_enabled="true"
-        android:drawable="@drawable/btn_dial_action_right_pressed" />
-    <item android:state_focused="true" android:state_enabled="true"
-        android:drawable="@drawable/btn_dial_action_right_selected" />
-    <item android:state_enabled="true"
-        android:drawable="@drawable/btn_dial_action_right_normal" />
-</selector>
-
diff --git a/res/drawable/btn_dial_voicemail.xml b/res/drawable/btn_dial_voicemail.xml
deleted file mode 100644
index 8669f0f..0000000
--- a/res/drawable/btn_dial_voicemail.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- Background resource for dial voicemail button for the various 12 key dialers. -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <!-- Disabled views -->
-    <item android:state_focused="true" android:state_enabled="false"
-        android:drawable="@drawable/btn_dial_action_left_disable_focused" />
-    <item android:state_enabled="false"
-        android:drawable="@drawable/btn_dial_action_left_disable" />
-
-    <!-- Enabled views -->
-    <item android:state_pressed="true" android:state_enabled="true"
-        android:drawable="@drawable/btn_dial_action_left_pressed" />
-    <item android:state_focused="true" android:state_enabled="true"
-        android:drawable="@drawable/btn_dial_action_left_selected" />
-    <item android:state_enabled="true"
-        android:drawable="@drawable/btn_dial_action_left_normal" />
-</selector>
diff --git a/res/drawable/call_background_secondary.xml b/res/drawable/call_background_secondary.xml
deleted file mode 100644
index b784862..0000000
--- a/res/drawable/call_background_secondary.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_window_focused="false"
-        android:drawable="@android:color/transparent" />
-    <item android:state_focused="false" android:state_pressed="true"
-        android:drawable="@*android:drawable/list_selector_background_transition" />
-    <item android:state_focused="false" android:state_pressed="false"
-        android:drawable="@color/background_secondary"/>
-
-</selector>
diff --git a/res/drawable/dial_num_1_no_vm.xml b/res/drawable/dial_num_1_no_vm.xml
deleted file mode 100644
index 201c4d2..0000000
--- a/res/drawable/dial_num_1_no_vm.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true"
-        android:drawable="@drawable/dial_num_1_no_vm_blk" />
-    <item android:state_focused="true"
-        android:drawable="@drawable/dial_num_1_no_vm_blk" />
-    <item
-        android:drawable="@drawable/dial_num_1_no_vm_wht" />
-</selector>
diff --git a/res/drawable/filter_selector_background.xml b/res/drawable/filter_selector_background.xml
deleted file mode 100644
index 16464f6..0000000
--- a/res/drawable/filter_selector_background.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true" android:drawable="@color/filter_selector_selected_background" />
-    <item android:drawable="@android:color/transparent"/>
-</selector>
diff --git a/res/drawable/list_item_background_secondary.xml b/res/drawable/list_item_background_secondary.xml
deleted file mode 100644
index 0a27206..0000000
--- a/res/drawable/list_item_background_secondary.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true" android:drawable="@android:color/transparent"/>
-    <item android:state_selected="true" android:drawable="@android:color/transparent"/>
-    <item android:drawable="@color/background_secondary"/> <!-- not selected -->
-</selector>
diff --git a/res/layout/call_detail.xml b/res/layout/call_detail.xml
index 6a03493..eca4835 100644
--- a/res/layout/call_detail.xml
+++ b/res/layout/call_detail.xml
@@ -47,26 +47,19 @@
 
         android:background="@drawable/ic_contact_picture"
     />
-    <ListView
-        android:id="@android:id/list"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_below="@id/contact_background"
-        android:background="?attr/call_log_primary_background_color"
-    />
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="?attr/call_detail_contact_background_overlay_height"
         android:background="#3F000000"
         android:layout_alignParentLeft="true"
-        android:layout_above="@android:id/list"
+        android:layout_alignBottom="@id/contact_background"
     />
     <RelativeLayout
-        android:id="@+id/photo_panel"
+        android:id="@+id/contact_text"
         android:layout_width="match_parent"
         android:layout_height="?attr/call_detail_contact_background_overlay_height"
         android:layout_alignParentLeft="true"
-        android:layout_above="@android:id/list"
+        android:layout_alignBottom="@id/contact_background"
         android:paddingLeft="5dip"
     >
         <RelativeLayout
@@ -87,42 +80,19 @@
             android:layout_alignParentBottom="true"
         />
     </RelativeLayout>
-    <RelativeLayout
-        android:id="@+id/call_panel"
+    <ListView
+        android:id="@android:id/list"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/contact_background"
+        android:background="?attr/call_log_primary_background_color"
+    />
+    <ListView
+        android:id="@+id/history"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_alignParentLeft="true"
         android:layout_below="@android:id/list"
-        android:paddingBottom="10dp"
-        android:paddingTop="10dp"
-        android:paddingLeft="80dp"
         android:background="?attr/call_log_secondary_background_color"
-    >
-        <TextView
-            android:id="@+id/time"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignParentLeft="true"
-            android:textColor="?attr/call_log_secondary_text_color"
-        />
-        <TextView
-            android:id="@+id/duration"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignParentLeft="true"
-            android:layout_below="@id/time"
-            android:layout_alignLeft="@id/time"
-            android:textColor="?attr/call_log_secondary_text_color"
-        />
-        <ImageView
-            android:id="@+id/delete"
-            android:layout_width="?attr/call_detail_action_icon_size"
-            android:layout_height="?attr/call_detail_action_icon_size"
-            android:layout_alignParentRight="true"
-            android:scaleType="center"
-            android:gravity="center_vertical"
-            android:src="@android:drawable/sym_action_call"
-            android:visibility="gone"
-        />
-    </RelativeLayout>
+    />
 </RelativeLayout>
diff --git a/res/layout/call_detail_history_item.xml b/res/layout/call_detail_history_item.xml
new file mode 100644
index 0000000..9377404
--- /dev/null
+++ b/res/layout/call_detail_history_item.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:background="?attr/call_log_secondary_background_color"
+    android:padding="5dip"
+>
+    <ImageView
+        android:id="@+id/call_type_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentLeft="true"
+        android:layout_marginRight="5dip"
+    />
+    <TextView
+        android:id="@+id/call_type_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_toRightOf="@id/call_type_icon"
+        android:textColor="?attr/call_log_secondary_text_color"
+    />
+    <TextView
+        android:id="@+id/number"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/call_type_text"
+        android:layout_alignLeft="@id/call_type_text"
+        android:textColor="?attr/call_log_secondary_text_color"
+    />
+    <TextView
+        android:id="@+id/date"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/number"
+        android:layout_alignLeft="@id/number"
+        android:textColor="?attr/call_log_secondary_text_color"
+    />
+    <TextView
+        android:id="@+id/duration"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/date"
+        android:layout_alignLeft="@id/date"
+        android:textColor="?attr/call_log_secondary_text_color"
+    />
+</RelativeLayout>
diff --git a/res/layout/call_detail_list_item.xml b/res/layout/call_detail_list_item.xml
index 78a5294..8b90e25 100644
--- a/res/layout/call_detail_list_item.xml
+++ b/res/layout/call_detail_list_item.xml
@@ -1,26 +1,22 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright 2009, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
 -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:minHeight="?android:attr/listPreferredItemHeight"
     android:orientation="horizontal"
     android:paddingLeft="9dip"
     android:paddingRight="5dip"
diff --git a/res/layout/call_log_list_group_item.xml b/res/layout/call_log_list_group_item.xml
index 57465a6..0eaeaa6 100644
--- a/res/layout/call_log_list_group_item.xml
+++ b/res/layout/call_log_list_group_item.xml
@@ -18,8 +18,7 @@
     android:layout_width="match_parent"
     android:layout_height="?attr/call_log_list_item_height"
 >
-
     <include layout="@layout/call_log_contact_photo"/>
-    <include layout="@layout/call_log_action_group"/>
+    <include layout="@layout/call_log_action_call"/>
     <include layout="@layout/call_log_list_item_layout" />
 </RelativeLayout>
diff --git a/res/layout/call_log_phone_call_details.xml b/res/layout/call_log_phone_call_details.xml
index f22efba..3f46c8d 100644
--- a/res/layout/call_log_phone_call_details.xml
+++ b/res/layout/call_log_phone_call_details.xml
@@ -26,6 +26,7 @@
             android:id="@+id/call_type_icons"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:gravity="bottom"
         />
         <TextView
             android:id="@+id/call_type_name"
@@ -43,18 +44,18 @@
             android:textColor="?attr/call_log_primary_text_color"
             android:text="@string/call_log_type_date_separator"
         />
+        <TextView
+            android:id="@+id/date"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="?attr/call_log_primary_text_color"
+            android:layout_toRightOf="@id/call_type"
+            android:layout_marginLeft="?attr/call_log_date_margin"
+            android:layout_alignParentBottom="true"
+        />
     </LinearLayout>
     <TextView
-        android:id="@+id/date"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textAppearance="?android:attr/textAppearanceSmall"
-        android:textColor="?attr/call_log_primary_text_color"
-        android:layout_toRightOf="@id/call_type"
-        android:layout_marginLeft="?attr/call_log_date_margin"
-        android:layout_alignParentBottom="true"
-    />
-    <TextView
         android:id="@+id/number"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/res/layout/contact_detail_header_view_list_item.xml b/res/layout/contact_detail_header_view_list_item.xml
deleted file mode 100644
index cf149df..0000000
--- a/res/layout/contact_detail_header_view_list_item.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<com.android.contacts.detail.ContactDetailHeaderView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/contact_header_widget"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"/>
\ No newline at end of file
diff --git a/res/layout/contact_tile_starred_secondary_target.xml b/res/layout/contact_tile_starred_secondary_target.xml
new file mode 100644
index 0000000..a8ae00f
--- /dev/null
+++ b/res/layout/contact_tile_starred_secondary_target.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<view
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    class="com.android.contacts.list.ContactTileSecondaryTargetView"
+    style="@style/ContactTileStarred" >
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" >
+
+        <ImageView
+            android:id="@+id/contact_tile_image"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:scaleType="centerCrop" />
+
+        <View
+            android:id="@+id/contact_tile_background"
+            style="@style/ContactTileStarredTextBackground" />
+
+        <LinearLayout
+            android:orientation="horizontal"
+            style="@style/ContactTileStarredText">
+
+            <TextView
+                android:id="@+id/contact_tile_name"
+                style="@style/ContactTileStarredText"
+                android:layout_width="0dip"
+                android:layout_weight="2" />
+
+            <ImageButton
+                android:id="@+id/contact_tile_secondary_button"
+                android:src="@drawable/ic_tab_unselected_contacts"
+                android:layout_height="match_parent"
+                android:layout_width="0dip"
+                android:layout_weight="1" />
+
+        </LinearLayout>
+
+    </RelativeLayout>
+
+</view>
diff --git a/res/layout/contacts_search_content.xml b/res/layout/contacts_search_content.xml
deleted file mode 100644
index d36ad00..0000000
--- a/res/layout/contacts_search_content.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:id="@+id/pinned_header_list_layout"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        android:background="@color/translucent_search_background"
-        >
-
-    <include android:id="@+id/searchView"
-        layout="@layout/search_bar"/>
-
-    <FrameLayout
-        android:id="@+id/list_container"
-        android:layout_width="match_parent"
-        android:layout_height="0dip"
-        android:layout_weight="1"
-        android:fastScrollEnabled="true"
-        android:background="@android:color/background_dark"
-    />
-
-    <!-- Transparent filler -->
-    <View android:id="@android:id/empty"
-        android:layout_width="match_parent"
-        android:layout_height="0dip"
-        android:layout_weight="1"
-        android:visibility="gone"
-    />
-    <ViewStub android:id="@+id/footer_stub"
-        android:layout="@layout/footer_panel"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content"
-    />
-</LinearLayout>
diff --git a/res/layout/people_activity.xml b/res/layout/people_activity.xml
index 11431b3..589e4a9 100644
--- a/res/layout/people_activity.xml
+++ b/res/layout/people_activity.xml
@@ -19,28 +19,18 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <!-- Favorites -->
-    <fragment
-        android:id="@+id/favorites_fragment"
-        class="com.android.contacts.list.StrequentContactListFragment"
-        android:layout_height="match_parent"
-        android:layout_width="match_parent" />
+    <!--
+        ViewPager for swiping between tabs.  We put StrequentContactListFragment,
+        DefaultContactBrowseListFragment and GroupBrowseListFragment at runtime.
 
-    <!-- All -->
-    <fragment
-        android:id="@+id/all_fragment"
-        class="com.android.contacts.list.DefaultContactBrowseListFragment"
+        (Adding them directly as the children of this view is not recommended.  ViewPager should
+        be treated like a ListView, which doesn't expect children to be added from the layout.)
+    -->
+    <android.support.v4.view.ViewPager
+        android:id="@+id/tab_pager"
         android:layout_height="match_parent"
         android:layout_width="match_parent"
-    />
-
-    <!-- Groups -->
-    <fragment
-        android:id="@+id/groups_fragment"
-        class="com.android.contacts.group.GroupBrowseListFragment"
-        android:layout_height="match_parent"
-        android:layout_width="match_parent"
-    />
+        />
 
     <FrameLayout
         android:id="@+id/contacts_unavailable_view"
diff --git a/res/layout/tab_indicator.xml b/res/layout/tab_indicator.xml
deleted file mode 100644
index d43265c..0000000
--- a/res/layout/tab_indicator.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="@dimen/tab_height"
-    android:layout_weight="1"
-    android:layout_marginLeft="-3dip"
-    android:layout_marginRight="-3dip"
-    android:minWidth="72dip"
-    android:background="@+drawable/tab_indicator_bg">
-
-    <ImageView android:id="@+id/tab_icon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_centerInParent="true"
-    />
-
-    <TextView android:id="@+id/tab_title"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentBottom="true"
-        android:layout_centerHorizontal="true"
-        android:textColor="@+color/tab_indicator_text"
-        android:textSize="20dip"
-    />
-
-</RelativeLayout>
diff --git a/res/menu/actions.xml b/res/menu/actions.xml
index 7bd3765..fd2b967 100644
--- a/res/menu/actions.xml
+++ b/res/menu/actions.xml
@@ -17,17 +17,20 @@
     <item
         android:id="@+id/menu_search"
         android:icon="@android:drawable/ic_menu_search"
-        android:title="@string/menu_search" />
+        android:title="@string/menu_search"
+        android:showAsAction="ifRoom" />
 
     <item
         android:id="@+id/menu_add_contact"
         android:icon="@drawable/ic_menu_add_contact_holo_light"
-        android:title="@string/menu_new_contact_action_bar" />
+        android:title="@string/menu_new_contact_action_bar"
+        android:showAsAction="ifRoom" />
 
     <item
         android:id="@+id/menu_add_group"
         android:icon="@drawable/ic_menu_display_all_holo_light"
-        android:title="@string/menu_new_group_action_bar" />
+        android:title="@string/menu_new_group_action_bar"
+        android:showAsAction="ifRoom" />
 
     <item
         android:id="@+id/menu_contacts_filter"
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 01f0e62..8fdccfc 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -161,7 +161,7 @@
         <attr name="call_log_list_item_height" format="dimension" />
     </declare-styleable>
 
-    <style name="PeopleTheme" parent="android:Theme.Holo.Light">
+    <style name="PeopleTheme" parent="android:Theme.Holo.Light.SplitActionBarWhenNarrow">
         <item name="list_item_height">?android:attr/listPreferredItemHeight</item>
         <item name="activated_background">@drawable/list_item_activated_background</item>
         <item name="section_header_background">@drawable/list_title_holo</item>
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index d08b76a..5f55f80 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -16,7 +16,9 @@
 
 package com.android.contacts;
 
-import com.android.internal.telephony.CallerInfo;
+import com.android.contacts.calllog.CallDetailHistoryAdapter;
+import com.android.contacts.calllog.CallTypeHelper;
+import com.android.contacts.calllog.PhoneNumberHelper;
 
 import android.app.ListActivity;
 import android.content.ContentResolver;
@@ -35,7 +37,7 @@
 import android.telephony.PhoneNumberUtils;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
-import android.text.format.DateUtils;
+import android.util.Log;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -43,6 +45,7 @@
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.ImageView;
+import android.widget.ListView;
 import android.widget.TextView;
 import android.widget.Toast;
 
@@ -51,16 +54,22 @@
 
 /**
  * Displays the details of a specific call log entry.
+ * <p>
+ * This activity can be either started with the URI of a single call log entry, or with the
+ * {@link #EXTRA_CALL_LOG_IDS} extra to specify a group of call log entries.
  */
 public class CallDetailActivity extends ListActivity implements
         AdapterView.OnItemClickListener {
     private static final String TAG = "CallDetail";
 
+    /** A long array extra containing ids of call log entries to display. */
+    public static final String EXTRA_CALL_LOG_IDS = "com.android.contacts.CALL_LOG_IDS";
+
     /** The views representing the details of a phone call. */
     private PhoneCallDetailsViews mPhoneCallDetailsViews;
+    private CallTypeHelper mCallTypeHelper;
+    private PhoneNumberHelper mPhoneNumberHelper;
     private PhoneCallDetailsHelper mPhoneCallDetailsHelper;
-    private TextView mCallTimeView;
-    private TextView mCallDurationView;
     private View mHomeActionView;
     private ImageView mMainActionView;
     private ImageView mContactBackgroundView;
@@ -72,7 +81,6 @@
     /* package */ Resources mResources;
     /** Helper to load contact photos. */
     private ContactPhotoManager mContactPhotoManager;
-    /** Attached to the call action button in the UI. */
 
     static final String[] CALL_LOG_PROJECTION = new String[] {
         CallLog.Calls.DATE,
@@ -115,17 +123,17 @@
         mResources = getResources();
 
         mPhoneCallDetailsViews = PhoneCallDetailsViews.fromView(getWindow().getDecorView());
-        mPhoneCallDetailsHelper = new PhoneCallDetailsHelper(this, getResources(),
-                getVoicemailNumber(),
-                getResources().getDrawable(R.drawable.ic_call_log_list_incoming_call),
-                getResources().getDrawable(R.drawable.ic_call_log_list_outgoing_call),
-                getResources().getDrawable(R.drawable.ic_call_log_list_missed_call),
-                getResources().getDrawable(R.drawable.ic_call_log_list_voicemail));
+        mCallTypeHelper = new CallTypeHelper(getResources(),
+                getResources().getDrawable(R.drawable.ic_call_incoming_holo_dark),
+                getResources().getDrawable(R.drawable.ic_call_outgoing_holo_dark),
+                getResources().getDrawable(R.drawable.ic_call_missed_holo_dark),
+                getResources().getDrawable(R.drawable.ic_call_voicemail_holo_dark));
+        mPhoneNumberHelper = new PhoneNumberHelper(mResources, getVoicemailNumber());
+        mPhoneCallDetailsHelper = new PhoneCallDetailsHelper(this, mResources, mCallTypeHelper,
+                mPhoneNumberHelper);
         mHomeActionView = findViewById(R.id.action_bar_home);
         mMainActionView = (ImageView) findViewById(R.id.main_action);
         mContactBackgroundView = (ImageView) findViewById(R.id.contact_background);
-        mCallTimeView = (TextView) findViewById(R.id.time);
-        mCallDurationView = (TextView) findViewById(R.id.duration);
         mDefaultCountryIso = ContactsUtils.getCurrentCountryIso(this);
         mContactPhotoManager = ContactPhotoManager.getInstance(this);
         getListView().setOnItemClickListener(this);
@@ -142,7 +150,29 @@
     @Override
     public void onResume() {
         super.onResume();
-        updateData(getIntent().getData());
+        updateData(getCallLogEntryUris());
+    }
+
+    /**
+     * Returns the list of URIs to show.
+     * <p>
+     * There are two ways the URIs can be provided to the activity: as the data on the intent, or as
+     * a list of ids in the call log added as an extra on the URI.
+     * <p>
+     * If both are available, the data on the intent takes precedence.
+     */
+    private Uri[] getCallLogEntryUris() {
+        Uri uri = getIntent().getData();
+        if (uri != null) {
+            // If there is a data on the intent, it takes precedence over the extra.
+            return new Uri[]{ uri };
+        }
+        long[] ids = getIntent().getLongArrayExtra(EXTRA_CALL_LOG_IDS);
+        Uri[] uris = new Uri[ids.length];
+        for (int index = 0; index < ids.length; ++index) {
+            uris[index] = ContentUris.withAppendedId(Calls.CONTENT_URI_WITH_VOICEMAIL, ids[index]);
+        }
+        return uris;
     }
 
     @Override
@@ -167,154 +197,200 @@
     /**
      * Update user interface with details of given call.
      *
-     * @param callUri Uri into {@link CallLog.Calls}
+     * @param callUris URIs into {@link CallLog.Calls} of the calls to be displayed
      */
-    private void updateData(final Uri callUri) {
+    private void updateData(final Uri... callUris) {
+        // TODO: All phone calls correspond to the same person, so we can make a single lookup.
+        final int numCalls = callUris.length;
+        final PhoneCallDetails[] details = new PhoneCallDetails[numCalls];
+        try {
+            for (int index = 0; index < numCalls; ++index) {
+                details[index] = getPhoneCallDetailsForUri(callUris[index]);
+            }
+        } catch (IllegalArgumentException e) {
+            // Something went wrong reading in our primary data, so we're going to
+            // bail out and show error to users.
+            Log.w(TAG, "invalid URI starting call details", e);
+            Toast.makeText(this, R.string.toast_call_detail_error,
+                    Toast.LENGTH_SHORT).show();
+            finish();
+            return;
+        }
+
+        // We know that all calls are from the same number and the same contact, so pick the first.
+        mNumber = details[0].number.toString();
+        final long personId = details[0].personId;
+        final long photoId = details[0].photoId;
+
+        // Set the details header, based on the first phone call.
+        mPhoneCallDetailsHelper.setPhoneCallDetails(mPhoneCallDetailsViews,
+                details[0], false);
+
+        // Cache the details about the phone number.
+        final Uri numberCallUri = mPhoneNumberHelper.getCallUri(mNumber);
+        final boolean canPlaceCallsTo = mPhoneNumberHelper.canPlaceCallsTo(mNumber);
+        final boolean isVoicemailNumber = mPhoneNumberHelper.isVoicemailNumber(mNumber);
+        final boolean isSipNumber = mPhoneNumberHelper.isSipNumber(mNumber);
+
+        // Let user view contact details if they exist, otherwise add option to create new contact
+        // from this number.
+        final Intent mainActionIntent;
+        final int mainActionIcon;
+
+        if (details[0].personId != -1) {
+            Uri personUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, personId);
+            mainActionIntent = new Intent(Intent.ACTION_VIEW, personUri);
+            mainActionIcon = R.drawable.sym_action_view_contact;
+        } else if (isVoicemailNumber) {
+            mainActionIntent = null;
+            mainActionIcon = 0;
+        } else if (isSipNumber) {
+            // TODO: This item is currently disabled for SIP addresses, because
+            // the Insert.PHONE extra only works correctly for PSTN numbers.
+            //
+            // To fix this for SIP addresses, we need to:
+            // - define ContactsContract.Intents.Insert.SIP_ADDRESS, and use it here if
+            //   the current number is a SIP address
+            // - update the contacts UI code to handle Insert.SIP_ADDRESS by
+            //   updating the SipAddress field
+            // and then we can remove the "!isSipNumber" check above.
+            mainActionIntent = null;
+            mainActionIcon = 0;
+        } else {
+            mainActionIntent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
+            mainActionIntent.setType(Contacts.CONTENT_ITEM_TYPE);
+            mainActionIntent.putExtra(Insert.PHONE, mNumber);
+            mainActionIcon = R.drawable.sym_action_add;
+        }
+
+        if (mainActionIntent == null) {
+            mMainActionView.setVisibility(View.INVISIBLE);
+        } else {
+            mMainActionView.setVisibility(View.VISIBLE);
+            mMainActionView.setImageResource(mainActionIcon);
+            mMainActionView.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    startActivity(mainActionIntent);
+                }
+            });
+        }
+
+        // Build list of various available actions.
+        final List<ViewEntry> actions = new ArrayList<ViewEntry>();
+
+        // This action allows to call the number that places the call.
+        if (canPlaceCallsTo) {
+            actions.add(new ViewEntry(android.R.drawable.sym_action_call,
+                    getString(R.string.menu_callNumber, mNumber),
+                    new Intent(Intent.ACTION_CALL_PRIVILEGED, numberCallUri)));
+        }
+
+        // This action allows to send an SMS to the number that placed the call.
+        if (mPhoneNumberHelper.canSendSmsTo(mNumber)) {
+            Intent smsIntent = new Intent(Intent.ACTION_SENDTO,
+                    Uri.fromParts("sms", mNumber, null));
+            actions.add(new ViewEntry(R.drawable.sym_action_sms,
+                    getString(R.string.menu_sendTextMessage), smsIntent));
+        }
+
+        // This action deletes all elements in the group from the call log.
+        actions.add(new ViewEntry(android.R.drawable.ic_menu_close_clear_cancel,
+                getString(R.string.recentCalls_removeFromRecentList),
+                new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        StringBuilder callIds = new StringBuilder();
+                        for (Uri callUri : callUris) {
+                            if (callIds.length() != 0) {
+                                callIds.append(",");
+                            }
+                            callIds.append(ContentUris.parseId(callUri));
+                        }
+
+                        getContentResolver().delete(Calls.CONTENT_URI_WITH_VOICEMAIL,
+                                Calls._ID + " IN (" + callIds + ")", null);
+                        finish();
+                    }
+                }));
+
+        if (canPlaceCallsTo && !isSipNumber && !isVoicemailNumber) {
+            // "Edit the number before calling" is only available for PSTN numbers.
+            actions.add(new ViewEntry(android.R.drawable.sym_action_call,
+                    getString(R.string.recentCalls_editNumberBeforeCall),
+                    new Intent(Intent.ACTION_DIAL, numberCallUri)));
+        }
+
+        // Set the actions for this phone number.
+        setListAdapter(new ViewAdapter(this, actions));
+
+        ListView historyList = (ListView) findViewById(R.id.history);
+        historyList.setAdapter(
+                new CallDetailHistoryAdapter(this, mInflater, mCallTypeHelper, details));
+        loadContactPhotos(photoId);
+    }
+
+    /** Return the phone call details for a given call log URI. */
+    private PhoneCallDetails getPhoneCallDetailsForUri(Uri callUri) {
         ContentResolver resolver = getContentResolver();
         Cursor callCursor = resolver.query(callUri, CALL_LOG_PROJECTION, null, null, null);
         try {
-            if (callCursor != null && callCursor.moveToFirst()) {
-                // Read call log specifics
-                mNumber = callCursor.getString(NUMBER_COLUMN_INDEX);
-                long date = callCursor.getLong(DATE_COLUMN_INDEX);
-                long duration = callCursor.getLong(DURATION_COLUMN_INDEX);
-                int callType = callCursor.getInt(CALL_TYPE_COLUMN_INDEX);
-                String countryIso = callCursor.getString(COUNTRY_ISO_COLUMN_INDEX);
-                if (TextUtils.isEmpty(countryIso)) {
-                    countryIso = mDefaultCountryIso;
-                }
-                // Pull out string in format [relative], [date]
-                CharSequence dateClause = DateUtils.formatDateRange(this, date, date,
-                        DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE |
-                        DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_SHOW_YEAR);
-                mCallTimeView.setText(dateClause);
-
-                // Set the duration
-                if (callType == Calls.MISSED_TYPE) {
-                    mCallDurationView.setVisibility(View.GONE);
-                } else {
-                    mCallDurationView.setVisibility(View.VISIBLE);
-                    mCallDurationView.setText(formatDuration(duration));
-                }
-
-                long photoId = 0L;
-                CharSequence nameText = "";
-                final CharSequence numberText;
-                int numberType = 0;
-                CharSequence numberLabel = "";
-                if (mNumber.equals(CallerInfo.UNKNOWN_NUMBER) ||
-                        mNumber.equals(CallerInfo.PRIVATE_NUMBER)) {
-                    numberText = getString(mNumber.equals(CallerInfo.PRIVATE_NUMBER)
-                            ? R.string.private_num : R.string.unknown);
-                    mMainActionView.setVisibility(View.GONE);
-                } else {
-                    // Perform a reverse-phonebook lookup to find the PERSON_ID
-                    Uri personUri = null;
-                    Uri phoneUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
-                            Uri.encode(mNumber));
-                    Cursor phonesCursor = resolver.query(
-                            phoneUri, PHONES_PROJECTION, null, null, null);
-                    String candidateNumberText = mNumber;
-                    try {
-                        if (phonesCursor != null && phonesCursor.moveToFirst()) {
-                            long personId = phonesCursor.getLong(COLUMN_INDEX_ID);
-                            personUri = ContentUris.withAppendedId(
-                                    Contacts.CONTENT_URI, personId);
-                            nameText = phonesCursor.getString(COLUMN_INDEX_NAME);
-                            photoId = phonesCursor.getLong(COLUMN_INDEX_PHOTO_ID);
-                            candidateNumberText = PhoneNumberUtils.formatNumber(
-                                    phonesCursor.getString(COLUMN_INDEX_NUMBER),
-                                    phonesCursor.getString(COLUMN_INDEX_NORMALIZED_NUMBER),
-                                    countryIso);
-                            numberType = phonesCursor.getInt(COLUMN_INDEX_TYPE);
-                            numberLabel = phonesCursor.getString(COLUMN_INDEX_LABEL);
-                        } else {
-                            candidateNumberText =
-                                    PhoneNumberUtils.formatNumber(mNumber, countryIso);
-                        }
-                    } finally {
-                        if (phonesCursor != null) phonesCursor.close();
-                        numberText = candidateNumberText;
-                    }
-
-                    // Let user view contact details if they exist, otherwise add option
-                    // to create new contact from this number.
-                    final Intent mainActionIntent;
-                    final int mainActionIcon;
-                    if (personUri != null) {
-                        mainActionIntent = new Intent(Intent.ACTION_VIEW, personUri);
-                        mainActionIcon = R.drawable.sym_action_view_contact;
-                    } else {
-                        mainActionIntent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
-                        mainActionIntent.setType(Contacts.CONTENT_ITEM_TYPE);
-                        mainActionIntent.putExtra(Insert.PHONE, mNumber);
-                        mainActionIcon = R.drawable.sym_action_add;
-                    }
-
-                    mMainActionView.setVisibility(View.VISIBLE);
-                    mMainActionView.setImageResource(mainActionIcon);
-                    mMainActionView.setOnClickListener(new View.OnClickListener() {
-                        @Override
-                        public void onClick(View v) {
-                            startActivity(mainActionIntent);
-                        }
-                    });
-
-                    // Build list of various available actions
-                    List<ViewEntry> actions = new ArrayList<ViewEntry>();
-
-                    final boolean isSipNumber = PhoneNumberUtils.isUriNumber(mNumber);
-                    final Uri numberCallUri;
-                    if (isSipNumber) {
-                        numberCallUri = Uri.fromParts("sip", mNumber, null);
-                    } else {
-                        numberCallUri = Uri.fromParts("tel", mNumber, null);
-                    }
-
-                    actions.add(new ViewEntry(android.R.drawable.sym_action_call,
-                            getString(R.string.menu_callNumber, mNumber),
-                            new Intent(Intent.ACTION_CALL_PRIVILEGED, numberCallUri)));
-
-                    if (!isSipNumber) {
-                        Intent smsIntent = new Intent(Intent.ACTION_SENDTO,
-                                Uri.fromParts("sms", mNumber, null));
-                        actions.add(new ViewEntry(R.drawable.sym_action_sms,
-                                getString(R.string.menu_sendTextMessage), smsIntent));
-                    }
-
-                    actions.add(new ViewEntry(android.R.drawable.ic_menu_close_clear_cancel,
-                            getString(R.string.recentCalls_removeFromRecentList),
-                            new View.OnClickListener() {
-                                @Override
-                                public void onClick(View v) {
-                                    long id = ContentUris.parseId(callUri);
-                                    getContentResolver().delete(Calls.CONTENT_URI_WITH_VOICEMAIL,
-                                            Calls._ID + " = ?", new String[]{Long.toString(id)});
-                                    finish();
-                                }
-                            }));
-
-                    if (!isSipNumber) {
-                        actions.add(new ViewEntry(android.R.drawable.sym_action_call,
-                                getString(R.string.recentCalls_editNumberBeforeCall),
-                                new Intent(Intent.ACTION_DIAL, numberCallUri)));
-                    }
-
-                    ViewAdapter adapter = new ViewAdapter(this, actions);
-                    setListAdapter(adapter);
-                }
-                mPhoneCallDetailsHelper.setPhoneCallDetails(mPhoneCallDetailsViews,
-                        new PhoneCallDetails(mNumber, numberText, new int[]{ callType }, date,
-                                nameText, numberType, numberLabel), false);
-
-                loadContactPhotos(photoId);
-            } else {
-                // Something went wrong reading in our primary data, so we're going to
-                // bail out and show error to users.
-                Toast.makeText(this, R.string.toast_call_detail_error,
-                        Toast.LENGTH_SHORT).show();
-                finish();
+            if (callCursor == null || !callCursor.moveToFirst()) {
+                throw new IllegalArgumentException("Cannot find content: " + callUri);
             }
+
+            // Read call log specifics.
+            String number = callCursor.getString(NUMBER_COLUMN_INDEX);
+            long date = callCursor.getLong(DATE_COLUMN_INDEX);
+            long duration = callCursor.getLong(DURATION_COLUMN_INDEX);
+            int callType = callCursor.getInt(CALL_TYPE_COLUMN_INDEX);
+            String countryIso = callCursor.getString(COUNTRY_ISO_COLUMN_INDEX);
+            if (TextUtils.isEmpty(countryIso)) {
+                countryIso = mDefaultCountryIso;
+            }
+
+            // Formatted phone number.
+            final CharSequence numberText;
+            // Read contact specifics.
+            CharSequence nameText = "";
+            int numberType = 0;
+            CharSequence numberLabel = "";
+            long personId = -1L;
+            long photoId = 0L;
+            // If this is not a regular number, there is no point in looking it up in the contacts.
+            if (!mPhoneNumberHelper.canPlaceCallsTo(number)) {
+                numberText = mPhoneNumberHelper.getDisplayNumber(number, null);
+            } else {
+                // Perform a reverse-phonebook lookup to find the contact details.
+                Uri phoneUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
+                        Uri.encode(number));
+                Cursor phonesCursor = resolver.query(phoneUri, PHONES_PROJECTION, null, null, null);
+                String candidateNumberText = number;
+                try {
+                    if (phonesCursor != null && phonesCursor.moveToFirst()) {
+                        personId = phonesCursor.getLong(COLUMN_INDEX_ID);
+                        nameText = phonesCursor.getString(COLUMN_INDEX_NAME);
+                        photoId = phonesCursor.getLong(COLUMN_INDEX_PHOTO_ID);
+                        candidateNumberText = PhoneNumberUtils.formatNumber(
+                                phonesCursor.getString(COLUMN_INDEX_NUMBER),
+                                phonesCursor.getString(COLUMN_INDEX_NORMALIZED_NUMBER),
+                                countryIso);
+                        numberType = phonesCursor.getInt(COLUMN_INDEX_TYPE);
+                        numberLabel = phonesCursor.getString(COLUMN_INDEX_LABEL);
+                    } else {
+                        // We could not find this contact in the contacts, just format the phone
+                        // number as best as we can. All the other fields will have their default
+                        // values.
+                        candidateNumberText =
+                                PhoneNumberUtils.formatNumber(number, countryIso);
+                    }
+                } finally {
+                    if (phonesCursor != null) phonesCursor.close();
+                    numberText = candidateNumberText;
+                }
+            }
+            return new PhoneCallDetails(number, numberText, new int[]{ callType }, date, duration,
+                    nameText, numberType, numberLabel, personId, photoId);
         } finally {
             if (callCursor != null) {
                 callCursor.close();
@@ -327,19 +403,6 @@
         mContactPhotoManager.loadPhoto(mContactBackgroundView, photoId);
     }
 
-    private String formatDuration(long elapsedSeconds) {
-        long minutes = 0;
-        long seconds = 0;
-
-        if (elapsedSeconds >= 60) {
-            minutes = elapsedSeconds / 60;
-            elapsedSeconds -= minutes * 60;
-        }
-        seconds = elapsedSeconds;
-
-        return getString(R.string.callDetailsDurationFormat, minutes, seconds);
-    }
-
     private String getVoicemailNumber() {
         TelephonyManager telephonyManager =
                 (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
diff --git a/src/com/android/contacts/ContactsActivity.java b/src/com/android/contacts/ContactsActivity.java
index b78fad2..020d135 100644
--- a/src/com/android/contacts/ContactsActivity.java
+++ b/src/com/android/contacts/ContactsActivity.java
@@ -19,10 +19,14 @@
 import com.android.contacts.test.InjectedServices;
 
 import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
 import android.content.ContentResolver;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.Bundle;
+import android.view.View;
 
 /**
  * A common superclass for Contacts activities that handles application-wide services.
@@ -86,4 +90,40 @@
     public void onServiceCompleted(Intent callbackIntent) {
         onNewIntent(callbackIntent);
     }
+
+    /**
+     * Convenient version of {@link FragmentManager#findFragmentById(int)}, which throws
+     * an exception if the fragment doesn't exist.
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends Fragment> T getFragment(int id) {
+        T result = (T)getFragmentManager().findFragmentById(id);
+        if (result == null) {
+            throw new IllegalArgumentException("fragment 0x" + Integer.toHexString(id)
+                    + " doesn't exist");
+        }
+        return result;
+    }
+
+    /**
+     * Convenient version of {@link #findViewById(int)}, which throws
+     * an exception if the view doesn't exist.
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends View> T getView(int id) {
+        T result = (T)findViewById(id);
+        if (result == null) {
+            throw new IllegalArgumentException("view 0x" + Integer.toHexString(id)
+                    + " doesn't exist");
+        }
+        return result;
+    }
+
+    protected static void showFragment(FragmentTransaction ft, Fragment f) {
+        if ((f != null) && f.isHidden()) ft.show(f);
+    }
+
+    protected static void hideFragment(FragmentTransaction ft, Fragment f) {
+        if ((f != null) && !f.isHidden()) ft.hide(f);
+    }
 }
diff --git a/src/com/android/contacts/PhoneCallDetails.java b/src/com/android/contacts/PhoneCallDetails.java
index 7b02a88..6ab47aa 100644
--- a/src/com/android/contacts/PhoneCallDetails.java
+++ b/src/com/android/contacts/PhoneCallDetails.java
@@ -35,28 +35,38 @@
     public final int[] callTypes;
     /** The date of the call, in milliseconds since the epoch. */
     public final long date;
+    /** The duration of the call in milliseconds, or 0 for missed calls. */
+    public final long duration;
     /** The name of the contact, or the empty string. */
     public final CharSequence name;
     /** The type of phone, e.g., {@link Phone#TYPE_HOME}, 0 if not available. */
     public final int numberType;
     /** The custom label associated with the phone number in the contact, or the empty string. */
     public final CharSequence numberLabel;
+    /** The id of the contact associated with this phone call. */
+    public final long personId;
+    /** The photo id of the contact associated with this phone call. */
+    public final long photoId;
 
     /** Create the details for a call with a number not associated with a contact. */
     public PhoneCallDetails(CharSequence number, CharSequence formattedNumber, int[] callTypes,
-            long date) {
-        this(number, formattedNumber, callTypes, date, "", 0, "");
+            long date, long duration) {
+        this(number, formattedNumber, callTypes, date, duration, "", 0, "", -1L, 0L);
     }
 
     /** Create the details for a call with a number associated with a contact. */
     public PhoneCallDetails(CharSequence number, CharSequence formattedNumber, int[] callTypes,
-            long date, CharSequence name, int numberType, CharSequence numberLabel) {
+            long date, long duration, CharSequence name, int numberType, CharSequence numberLabel,
+            long personId, long photoId) {
         this.number = number;
         this.formattedNumber = formattedNumber;
         this.callTypes = callTypes;
         this.date = date;
+        this.duration = duration;
         this.name = name;
         this.numberType = numberType;
         this.numberLabel = numberLabel;
+        this.personId = personId;
+        this.photoId = photoId;
     }
 }
diff --git a/src/com/android/contacts/PhoneCallDetailsHelper.java b/src/com/android/contacts/PhoneCallDetailsHelper.java
index 7f73b04..6bdfbaa 100644
--- a/src/com/android/contacts/PhoneCallDetailsHelper.java
+++ b/src/com/android/contacts/PhoneCallDetailsHelper.java
@@ -16,14 +16,13 @@
 
 package com.android.contacts;
 
+import com.android.contacts.calllog.CallTypeHelper;
+import com.android.contacts.calllog.PhoneNumberHelper;
 import com.android.contacts.format.FormatUtils;
-import com.android.internal.telephony.CallerInfo;
 
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-import android.provider.CallLog.Calls;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.telephony.PhoneNumberUtils;
 import android.text.Spanned;
@@ -38,25 +37,11 @@
 public class PhoneCallDetailsHelper {
     private final Context mContext;
     private final Resources mResources;
-    private final String mVoicemailNumber;
-    /** Icon for incoming calls. */
-    private final Drawable mIncomingDrawable;
-    /** Icon for outgoing calls. */
-    private final Drawable mOutgoingDrawable;
-    /** Icon for missed calls. */
-    private final Drawable mMissedDrawable;
-    /** Icon for voicemails. */
-    private final Drawable mVoicemailDrawable;
-    /** Name used to identify incoming calls. */
-    private final String mIncomingName;
-    /** Name used to identify outgoing calls. */
-    private final String mOutgoingName;
-    /** Name used to identify missed calls. */
-    private final String mMissedName;
-    /** Name used to identify voicemail calls. */
-    private final String mVoicemailName;
     /** The injected current time in milliseconds since the epoch. Used only by tests. */
     private Long mCurrentTimeMillisForTest;
+    // Helper classes.
+    private final CallTypeHelper mCallTypeHelper;
+    private final PhoneNumberHelper mPhoneNumberHelper;
 
     /**
      * Creates a new instance of the helper.
@@ -65,21 +50,12 @@
      *
      * @param resources used to look up strings
      */
-    public PhoneCallDetailsHelper(Context context, Resources resources, String voicemailNumber,
-            Drawable incomingDrawable, Drawable outgoingDrawable, Drawable missedDrawable,
-            Drawable voicemailDrawable) {
+    public PhoneCallDetailsHelper(Context context, Resources resources,
+            CallTypeHelper callTypeHelper, PhoneNumberHelper phoneNumberHelper) {
         mContext = context;
         mResources = resources;
-        mVoicemailNumber = voicemailNumber;
-        mIncomingDrawable = incomingDrawable;
-        mOutgoingDrawable = outgoingDrawable;
-        mMissedDrawable = missedDrawable;
-        mVoicemailDrawable = voicemailDrawable;
-        // Cache these values so that we do not need to look them up each time.
-        mIncomingName = mResources.getString(R.string.type_incoming);
-        mOutgoingName = mResources.getString(R.string.type_outgoing);
-        mMissedName = mResources.getString(R.string.type_missed);
-        mVoicemailName = mResources.getString(R.string.type_voicemail);
+        mCallTypeHelper = callTypeHelper;
+        mPhoneNumberHelper = phoneNumberHelper;
     }
 
     /** Fills the call details views with content. */
@@ -90,7 +66,7 @@
             int count = details.callTypes.length;
             for (int callType : details.callTypes) {
                 ImageView callTypeImage = new ImageView(mContext);
-                callTypeImage.setImageDrawable(getCallTypeDrawable(callType));
+                callTypeImage.setImageDrawable(mCallTypeHelper.getCallTypeDrawable(callType));
                 views.callTypeIcons.addView(callTypeImage);
             }
             views.callTypeIcons.setVisibility(View.VISIBLE);
@@ -101,7 +77,7 @@
             // Use the name of the first call type.
             // TODO: We should update this to handle the text for multiple calls as well.
             int callType = details.callTypes[0];
-            views.callTypeText.setText(getCallTypeText(callType));
+            views.callTypeText.setText(mCallTypeHelper.getCallTypeText(callType));
             views.callTypeIcons.removeAllViews();
 
             views.callTypeText.setVisibility(View.VISIBLE);
@@ -125,12 +101,13 @@
 
         final CharSequence nameText;
         final CharSequence numberText;
+        final CharSequence displayNumber =
+            mPhoneNumberHelper.getDisplayNumber(details.number, details.formattedNumber);
         if (TextUtils.isEmpty(details.name)) {
-            nameText = getDisplayNumber(details.number, details.formattedNumber);
+            nameText = displayNumber;
             numberText = "";
         } else {
             nameText = details.name;
-            CharSequence displayNumber = getDisplayNumber(details.number, details.formattedNumber);
             if (numberFormattedLabel != null) {
                 numberText = FormatUtils.applyStyleToSpan(Typeface.BOLD,
                         numberFormattedLabel + " " + displayNumber, 0,
@@ -155,69 +132,6 @@
         }
     }
 
-    /** Returns the text used to represent the given call type. */
-    private String getCallTypeText(int callType) {
-        switch (callType) {
-            case Calls.INCOMING_TYPE:
-                return mIncomingName;
-
-            case Calls.OUTGOING_TYPE:
-                return mOutgoingName;
-
-            case Calls.MISSED_TYPE:
-                return mMissedName;
-
-            case Calls.VOICEMAIL_TYPE:
-                return mVoicemailName;
-
-            default:
-                throw new IllegalArgumentException("invalid call type: " + callType);
-        }
-    }
-
-    /** Returns the drawable of the icon associated with the given call type. */
-    private Drawable getCallTypeDrawable(int callType) {
-        switch (callType) {
-            case Calls.INCOMING_TYPE:
-                return mIncomingDrawable;
-
-            case Calls.OUTGOING_TYPE:
-                return mOutgoingDrawable;
-
-            case Calls.MISSED_TYPE:
-                return mMissedDrawable;
-
-            case Calls.VOICEMAIL_TYPE:
-                return mVoicemailDrawable;
-
-            default:
-                throw new IllegalArgumentException("invalid call type: " + callType);
-        }
-    }
-
-    private CharSequence getDisplayNumber(CharSequence number, CharSequence formattedNumber) {
-        if (TextUtils.isEmpty(number)) {
-            return "";
-        }
-        if (number.equals(CallerInfo.UNKNOWN_NUMBER)) {
-            return mResources.getString(R.string.unknown);
-        }
-        if (number.equals(CallerInfo.PRIVATE_NUMBER)) {
-            return mResources.getString(R.string.private_num);
-        }
-        if (number.equals(CallerInfo.PAYPHONE_NUMBER)) {
-            return mResources.getString(R.string.payphone);
-        }
-        if (PhoneNumberUtils.extractNetworkPortion(number.toString()).equals(mVoicemailNumber)) {
-            return mResources.getString(R.string.voicemail);
-        }
-        if (TextUtils.isEmpty(formattedNumber)) {
-            return number;
-        } else {
-            return formattedNumber;
-        }
-    }
-
     public void setCurrentTimeForTest(long currentTimeMillis) {
         mCurrentTimeMillisForTest = currentTimeMillis;
     }
diff --git a/src/com/android/contacts/activities/ActionBarAdapter.java b/src/com/android/contacts/activities/ActionBarAdapter.java
index 3a183d2..0072592 100644
--- a/src/com/android/contacts/activities/ActionBarAdapter.java
+++ b/src/com/android/contacts/activities/ActionBarAdapter.java
@@ -22,7 +22,10 @@
 
 import android.app.ActionBar;
 import android.app.ActionBar.LayoutParams;
+import android.app.ActionBar.Tab;
+import android.app.FragmentTransaction;
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.os.Bundle;
 import android.text.TextUtils;
 import android.view.LayoutInflater;
@@ -42,6 +45,12 @@
         }
 
         void onAction(Action action);
+
+        /**
+         * Called when the user selects a tab.  The new tab can be obtained using
+         * {@link #getCurrentTab}.
+         */
+        void onSelectedTabChanged();
     }
 
     private static final String EXTRA_KEY_SEARCH_MODE = "navBar.searchMode";
@@ -59,27 +68,33 @@
 
     private Listener mListener;
 
-    private ActionBar mActionBar;
+    private final ActionBar mActionBar;
+    private final MyTabListener mTabListener = new MyTabListener();
 
+    public enum TabState {
+        FAVORITES, ALL, GROUPS;
 
-    public ActionBarAdapter(Context context, Listener listener) {
-        mContext = context;
-        mListener = listener;
-        mSearchLabelText = mContext.getString(R.string.search_label);
-        mAlwaysShowSearchView = mContext.getResources().getBoolean(R.bool.always_show_search_view);
+        public static TabState fromInt(int value) {
+            switch (value) {
+                case 0:
+                    return FAVORITES;
+                case 1:
+                    return ALL;
+                case 2:
+                    return GROUPS;
+            }
+            throw new IllegalArgumentException("Invalid value: " + value);
+        }
     }
 
-    public void onCreate(Bundle savedState, ContactsRequest request, ActionBar actionBar) {
-        mActionBar = actionBar;
-        mQueryString = null;
+    private TabState mCurrentTab = TabState.FAVORITES;
 
-        if (savedState != null) {
-            mSearchMode = savedState.getBoolean(EXTRA_KEY_SEARCH_MODE);
-            mQueryString = savedState.getString(EXTRA_KEY_QUERY);
-        } else {
-            mSearchMode = request.isSearchMode();
-            mQueryString = request.getQueryString();
-        }
+    public ActionBarAdapter(Context context, Listener listener, ActionBar actionBar) {
+        mContext = context;
+        mListener = listener;
+        mActionBar = actionBar;
+        mSearchLabelText = mContext.getString(R.string.search_label);
+        mAlwaysShowSearchView = mContext.getResources().getBoolean(R.bool.always_show_search_view);
 
         // Set up search view.
         View customSearchView = LayoutInflater.from(mContext).inflate(R.layout.custom_action_bar,
@@ -97,6 +112,30 @@
         mSearchView.setQuery(mQueryString, false);
         mActionBar.setCustomView(customSearchView, layoutParams);
 
+        mActionBar.setDisplayShowTitleEnabled(true);
+
+        // TODO Just use a boolean resource instead of styles.
+        TypedArray array = mContext.obtainStyledAttributes(null, R.styleable.ActionBarHomeIcon);
+        boolean showHomeIcon = array.getBoolean(R.styleable.ActionBarHomeIcon_show_home_icon, true);
+        array.recycle();
+        mActionBar.setDisplayShowHomeEnabled(showHomeIcon);
+
+        addTab(TabState.FAVORITES, mContext.getString(R.string.contactsFavoritesLabel));
+        addTab(TabState.ALL, mContext.getString(R.string.contactsAllLabel));
+        addTab(TabState.GROUPS, mContext.getString(R.string.contactsGroupsLabel));
+    }
+
+    public void initialize(Bundle savedState, ContactsRequest request) {
+        if (savedState == null) {
+            mSearchMode = request.isSearchMode();
+            mQueryString = request.getQueryString();
+        } else {
+            mSearchMode = savedState.getBoolean(EXTRA_KEY_SEARCH_MODE);
+            mQueryString = savedState.getString(EXTRA_KEY_QUERY);
+
+            // Just set to the field here.  The listener will be notified by update().
+            mCurrentTab = TabState.fromInt(savedState.getInt(EXTRA_KEY_SELECTED_TAB));
+        }
         update();
     }
 
@@ -104,6 +143,62 @@
         mListener = listener;
     }
 
+    private void addTab(TabState tabState, String text) {
+        final Tab tab = mActionBar.newTab();
+        tab.setTag(tabState);
+        tab.setText(text);
+        tab.setTabListener(mTabListener);
+        mActionBar.addTab(tab);
+    }
+
+    private class MyTabListener implements ActionBar.TabListener {
+        /**
+         * If true, it won't call {@link #setCurrentTab} in {@link #onTabSelected}.
+         * This flag is used when we want to programmatically update the current tab without
+         * {@link #onTabSelected} getting called.
+         */
+        public boolean mIgnoreTabSelected;
+
+        @Override public void onTabReselected(Tab tab, FragmentTransaction ft) { }
+        @Override public void onTabUnselected(Tab tab, FragmentTransaction ft) { }
+
+        @Override public void onTabSelected(Tab tab, FragmentTransaction ft) {
+            if (!mIgnoreTabSelected) {
+                setCurrentTab((TabState)tab.getTag());
+            }
+        }
+    }
+
+    /**
+     * Change the current tab, and notify the listener.
+     */
+    public void setCurrentTab(TabState tab) {
+        setCurrentTab(tab, true);
+    }
+
+    /**
+     * Change the current tab
+     */
+    public void setCurrentTab(TabState tab, boolean notifyListener) {
+        if (tab == null) throw new NullPointerException();
+        if (tab == mCurrentTab) {
+            return;
+        }
+        mCurrentTab = tab;
+
+        int index = mCurrentTab.ordinal();
+        if ((mActionBar.getNavigationMode() == ActionBar.NAVIGATION_MODE_TABS)
+                && (index != mActionBar.getSelectedNavigationIndex())) {
+            mActionBar.setSelectedNavigationItem(index);
+        }
+
+        if (notifyListener && mListener != null) mListener.onSelectedTabChanged();
+    }
+
+    public TabState getCurrentTab() {
+        return mCurrentTab;
+    }
+
     public boolean isSearchMode() {
         return mSearchMode;
     }
@@ -134,7 +229,7 @@
         }
     }
 
-    public void update() {
+    private void update() {
         if (mSearchMode) {
             mActionBar.setDisplayShowCustomEnabled(true);
             if (mAlwaysShowSearchView) {
@@ -144,16 +239,32 @@
                 // Phone -- search view gets focus
                 setFocusOnSearchView();
             }
-            mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+            if (mActionBar.getNavigationMode() != ActionBar.NAVIGATION_MODE_STANDARD) {
+                mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+            }
             if (mListener != null) {
                 mListener.onAction(Action.START_SEARCH_MODE);
             }
         } else {
             mActionBar.setDisplayShowCustomEnabled(mAlwaysShowSearchView);
-            mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+            if (mActionBar.getNavigationMode() != ActionBar.NAVIGATION_MODE_TABS) {
+                // setNavigationMode will trigger onTabSelected() with the tab which was previously
+                // selected.
+                // The issue is that when we're first switching to the tab navigation mode after
+                // screen orientation changes, onTabSelected() will get called with the first tab
+                // (i.e. favorite), which would results in mCurrentTab getting set to FAVORITES and
+                // we'd lose restored tab.
+                // So let's just disable the callback here temporarily.  We'll notify the listener
+                // after this anyway.
+                mTabListener.mIgnoreTabSelected = true;
+                mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+                mActionBar.setSelectedNavigationItem(mCurrentTab.ordinal());
+                mTabListener.mIgnoreTabSelected = false;
+            }
             mActionBar.setTitle(null);
             if (mListener != null) {
                 mListener.onAction(Action.STOP_SEARCH_MODE);
+                mListener.onSelectedTabChanged();
             }
         }
     }
@@ -192,16 +303,7 @@
     public void onSaveInstanceState(Bundle outState) {
         outState.putBoolean(EXTRA_KEY_SEARCH_MODE, mSearchMode);
         outState.putString(EXTRA_KEY_QUERY, mQueryString);
-        outState.putInt(EXTRA_KEY_SELECTED_TAB, mActionBar.getSelectedNavigationIndex());
-    }
-
-    public void onRestoreInstanceState(Bundle savedState) {
-        mSearchMode = savedState.getBoolean(EXTRA_KEY_SEARCH_MODE);
-        mQueryString = savedState.getString(EXTRA_KEY_QUERY);
-        int selectedTab = savedState.getInt(EXTRA_KEY_SELECTED_TAB);
-        if (selectedTab >= 0) {
-            mActionBar.setSelectedNavigationItem(selectedTab);
-        }
+        outState.putInt(EXTRA_KEY_SELECTED_TAB, mCurrentTab.ordinal());
     }
 
     private void setFocusOnSearchView() {
diff --git a/src/com/android/contacts/activities/DialtactsActivity.java b/src/com/android/contacts/activities/DialtactsActivity.java
index 0fa745d..3af9821 100644
--- a/src/com/android/contacts/activities/DialtactsActivity.java
+++ b/src/com/android/contacts/activities/DialtactsActivity.java
@@ -338,7 +338,6 @@
         } else if (fragment instanceof PhoneNumberPickerFragment) {
             mSearchFragment = (PhoneNumberPickerFragment) fragment;
             mSearchFragment.setOnPhoneNumberPickerActionListener(mPhoneNumberPickerActionListener);
-            mSearchFragment.setNameHighlightingEnabled(true);
             mSearchFragment.setQuickContactEnabled(true);
             final FragmentTransaction transaction = getFragmentManager().beginTransaction();
             if (mInSearchUi) {
diff --git a/src/com/android/contacts/activities/GroupDetailActivity.java b/src/com/android/contacts/activities/GroupDetailActivity.java
index c8f511b..7a74bfd 100644
--- a/src/com/android/contacts/activities/GroupDetailActivity.java
+++ b/src/com/android/contacts/activities/GroupDetailActivity.java
@@ -71,6 +71,11 @@
             intent.setAction(Intent.ACTION_EDIT);
             startActivity(intent);
         }
+
+        @Override
+        public void onContactSelected(Uri contactUri) {
+            startActivity(new Intent(Intent.ACTION_VIEW, contactUri));
+        }
     };
 
     @Override
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 12a17f2..500ad1e 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -20,6 +20,7 @@
 import com.android.contacts.ContactSaveService;
 import com.android.contacts.ContactsActivity;
 import com.android.contacts.R;
+import com.android.contacts.activities.ActionBarAdapter.TabState;
 import com.android.contacts.detail.ContactDetailFragment;
 import com.android.contacts.detail.ContactDetailLayoutController;
 import com.android.contacts.detail.ContactDetailTabCarousel;
@@ -33,7 +34,6 @@
 import com.android.contacts.interactions.ImportExportDialogFragment;
 import com.android.contacts.interactions.PhoneNumberInteraction;
 import com.android.contacts.list.AccountFilterActivity;
-import com.android.contacts.list.ContactBrowseListContextMenuAdapter;
 import com.android.contacts.list.ContactBrowseListFragment;
 import com.android.contacts.list.ContactEntryListFragment;
 import com.android.contacts.list.ContactListFilter;
@@ -56,12 +56,8 @@
 import com.android.contacts.util.AccountsListAdapter;
 import com.android.contacts.util.DialogManager;
 import com.android.contacts.util.PhoneCapabilityTester;
-import com.android.contacts.widget.ContextMenuAdapter;
 
 import android.accounts.Account;
-import android.app.ActionBar;
-import android.app.ActionBar.Tab;
-import android.app.ActionBar.TabListener;
 import android.app.Activity;
 import android.app.Fragment;
 import android.app.FragmentManager;
@@ -69,15 +65,17 @@
 import android.content.ActivityNotFoundException;
 import android.content.ContentValues;
 import android.content.Intent;
-import android.content.res.TypedArray;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Parcelable;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Intents;
 import android.provider.ContactsContract.ProviderStatus;
 import android.provider.Settings;
+import android.support.v13.app.FragmentPagerAdapter;
+import android.support.v4.view.PagerAdapter;
 import android.support.v4.view.ViewPager;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -86,11 +84,9 @@
 import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.view.Window;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.ListPopupWindow;
-import android.widget.SearchView;
 import android.widget.Toast;
 
 import java.util.ArrayList;
@@ -164,39 +160,14 @@
 
     private View mAddGroupImageView;
 
+    /** ViewPager for swipe, used only on the phone (i.e. one-pane mode) */
+    private ViewPager mTabPager;
+    private TabPagerAdapter mTabPagerAdapter;
+
     private ContactDetailLayoutController mContactDetailLayoutController;
 
     private final Handler mHandler = new Handler();
 
-    /**
-     * TODO: Use ViewPager so that tabs can be swiped left and right. Figure out how to use the
-     * support library in our app.
-     */
-    private final TabListener mTabListener = new TabListener() {
-        @Override
-        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
-            hideFragmentOnTabUnselect((TabState) tab.getTag(), ft);
-        }
-
-        @Override
-        public void onTabSelected(Tab tab, FragmentTransaction ft) {
-            final TabState tabState = (TabState) tab.getTag();
-            setSelectedTab(tabState);
-            showFragmentOnTabSelect(tabState, ft);
-            invalidateOptionsMenu();
-        }
-
-        @Override
-        public void onTabReselected(Tab tab, FragmentTransaction ft) {
-        }
-    };
-
-    private enum TabState {
-        FAVORITES, ALL, GROUPS
-    }
-
-    private TabState mSelectedTab;
-
     public PeopleActivity() {
         mIntentResolver = new ContactsIntentResolver(this);
         mContactListFilterController = new ContactListFilterController(this);
@@ -208,19 +179,22 @@
         return mProviderStatus == ProviderStatus.STATUS_NORMAL;
     }
 
+    /**
+     * Initialize fragments that are (or may not be) in the layout.
+     *
+     * For the fragments that are in the layout, we initialize them in
+     * {@link #configureContentView(boolean, Bundle)} after inflating the layout.
+     *
+     * However, there are special fragments which may not be in the layout, so we have to do the
+     * initialization here.
+     * The target fragments are:
+     * - {@link ContactDetailFragment} and {@link ContactDetailUpdatesFragment}:  They may not be
+     *   in the layout depending on the configuration.  (i.e. portrait)
+     * - {@link ContactsUnavailableFragment}: We always create it at runtime.
+     */
     @Override
     public void onAttachFragment(Fragment fragment) {
-        if (fragment instanceof DefaultContactBrowseListFragment) {
-            mAllFragment = (DefaultContactBrowseListFragment)fragment;
-            mAllFragment.setOnContactListActionListener(new ContactBrowserActionListener());
-            if (!getWindow().hasFeature(Window.FEATURE_ACTION_BAR)) {
-                mAllFragment.setContextMenuAdapter(
-                        new ContactBrowseListContextMenuAdapter(mAllFragment));
-            }
-        } else if (fragment instanceof GroupBrowseListFragment) {
-            mGroupsFragment = (GroupBrowseListFragment) fragment;
-            mGroupsFragment.setListener(new GroupBrowserActionListener());
-        } else if (fragment instanceof ContactDetailFragment) {
+        if (fragment instanceof ContactDetailFragment) {
             mContactDetailFragment = (ContactDetailFragment) fragment;
             mContactDetailFragment.setListener(mContactDetailFragmentListener);
         } else if (fragment instanceof ContactDetailUpdatesFragment) {
@@ -230,18 +204,6 @@
             mContactsUnavailableFragment.setProviderStatusLoader(mProviderStatusLoader);
             mContactsUnavailableFragment.setOnContactsUnavailableActionListener(
                     new ContactsUnavailableFragmentListener());
-        } else if (fragment instanceof ContactLoaderFragment) {
-            mContactDetailLoaderFragment = (ContactLoaderFragment) fragment;
-            mContactDetailLoaderFragment.setListener(mContactDetailLoaderFragmentListener);
-        } else if (fragment instanceof GroupDetailFragment) {
-            mGroupDetailFragment = (GroupDetailFragment) fragment;
-            mGroupDetailFragment.setListener(mGroupDetailFragmentListener);
-            mGroupDetailFragment.setQuickContact(PhoneCapabilityTester.isUsingTwoPanes(this));
-        } else if (fragment instanceof StrequentContactListFragment) {
-            mFavoritesFragment = (StrequentContactListFragment) fragment;
-            mFavoritesFragment.setListener(mFavoritesFragmentListener);
-            mFavoritesFragment.setDisplayType(DisplayType.STARRED_ONLY);
-            mFavoritesFragment.setQuickContact(PhoneCapabilityTester.isUsingTwoPanes(this));
         }
     }
 
@@ -275,39 +237,6 @@
             return;
         }
 
-        if (createContentView) {
-            setContentView(R.layout.people_activity);
-
-            mFavoritesView = findViewById(R.id.favorites_view);
-            mDetailsView = findViewById(R.id.details_view);
-            mBrowserView = findViewById(R.id.browse_view);
-
-            final FragmentManager fragmentManager = getFragmentManager();
-            mFavoritesFragment = (StrequentContactListFragment) fragmentManager
-                    .findFragmentById(R.id.favorites_fragment);
-            mFrequentFragment = (StrequentContactListFragment) fragmentManager
-                    .findFragmentById(R.id.frequent_fragment);
-            mAllFragment = (DefaultContactBrowseListFragment) fragmentManager
-                    .findFragmentById(R.id.all_fragment);
-            mGroupsFragment = (GroupBrowseListFragment) fragmentManager
-                    .findFragmentById(R.id.groups_fragment);
-            // Hide all tabs (the current tab will later be reshown once a tab is selected)
-            final FragmentTransaction transaction = fragmentManager.beginTransaction();
-            transaction.hide(mAllFragment);
-            transaction.hide(mGroupsFragment);
-
-            if (mFrequentFragment != null) {
-                mFrequentFragment.setDisplayType(DisplayType.FREQUENT_ONLY);
-            }
-            if (mContactDetailFragment != null) {
-                transaction.hide(mContactDetailFragment);
-            }
-            if (mGroupDetailFragment != null) {
-                transaction.hide(mGroupDetailFragment);
-            }
-            transaction.commit();
-        }
-
         if (mRequest.getActionCode() == ContactsRequest.ACTION_VIEW_CONTACT
                 && !PhoneCapabilityTester.isUsingTwoPanes(this)) {
             redirect = new Intent(this, ContactDetailActivity.class);
@@ -318,10 +247,105 @@
             return;
         }
 
+        if (createContentView) {
+            setContentView(R.layout.people_activity);
+
+            final FragmentManager fragmentManager = getFragmentManager();
+
+            // Hide all tabs (the current tab will later be reshown once a tab is selected)
+            final FragmentTransaction transaction = fragmentManager.beginTransaction();
+
+            // Prepare the fragments which are used both on 1-pane and on 2-pane.
+            if (PhoneCapabilityTester.isUsingTwoPanes(this)) {
+                mFavoritesFragment = getFragment(R.id.favorites_fragment);
+                mAllFragment = getFragment(R.id.all_fragment);
+                mGroupsFragment = getFragment(R.id.groups_fragment);
+            } else {
+                mTabPager = getView(R.id.tab_pager);
+                mTabPagerAdapter = new TabPagerAdapter();
+                mTabPager.setAdapter(mTabPagerAdapter);
+                mTabPager.setOnPageChangeListener(new TabPagerListener());
+
+                final String FAVORITE_TAG = "tab-pager-favorite";
+                final String ALL_TAG = "tab-pager-all";
+                final String GROUPS_TAG = "tab-pager-groups";
+
+                // Create the fragments and add as children of the view pager.
+                // The pager adapter will only change the visibility; it'll never create/destroy
+                // fragments.
+                // However, if it's after screen rotation, the fragments have been re-created by
+                // the fragment manager, so first see if there're already the target fragments
+                // existing.
+                mFavoritesFragment = (StrequentContactListFragment)
+                        fragmentManager.findFragmentByTag(FAVORITE_TAG);
+                mAllFragment = (DefaultContactBrowseListFragment)
+                        fragmentManager.findFragmentByTag(ALL_TAG);
+                mGroupsFragment = (GroupBrowseListFragment)
+                        fragmentManager.findFragmentByTag(GROUPS_TAG);
+
+                if (mFavoritesFragment == null) {
+                    mFavoritesFragment = new StrequentContactListFragment();
+                    mAllFragment = new DefaultContactBrowseListFragment();
+                    mGroupsFragment = new GroupBrowseListFragment();
+
+                    transaction.add(R.id.tab_pager, mFavoritesFragment, FAVORITE_TAG);
+                    transaction.add(R.id.tab_pager, mAllFragment, ALL_TAG);
+                    transaction.add(R.id.tab_pager, mGroupsFragment, GROUPS_TAG);
+                }
+            }
+
+            mFavoritesFragment.setListener(mFavoritesFragmentListener);
+
+            mAllFragment.setOnContactListActionListener(new ContactBrowserActionListener());
+
+            mGroupsFragment.setListener(new GroupBrowserActionListener());
+
+            // Hide all fragments for now.  We adjust visibility when we get onSelectedTabChanged()
+            // from ActionBarAdapter.
+            transaction.hide(mFavoritesFragment);
+            transaction.hide(mAllFragment);
+            transaction.hide(mGroupsFragment);
+
+            if (PhoneCapabilityTester.isUsingTwoPanes(this)) {
+                // Prepare 2-pane only fragments/views...
+
+                // Container views for fragments
+                mFavoritesView = getView(R.id.favorites_view);
+                mDetailsView = getView(R.id.details_view);
+                mBrowserView = getView(R.id.browse_view);
+
+                // 2-pane only fragments
+                mFrequentFragment = getFragment(R.id.frequent_fragment);
+                mFrequentFragment.setListener(mFavoritesFragmentListener);
+                mFrequentFragment.setDisplayType(DisplayType.FREQUENT_ONLY);
+                mFrequentFragment.setQuickContact(true);
+
+                mContactDetailLoaderFragment = getFragment(R.id.contact_detail_loader_fragment);
+                mContactDetailLoaderFragment.setListener(mContactDetailLoaderFragmentListener);
+
+                mGroupDetailFragment = getFragment(R.id.group_detail_fragment);
+                mGroupDetailFragment.setListener(mGroupDetailFragmentListener);
+                mGroupDetailFragment.setQuickContact(true);
+
+                transaction.hide(mContactDetailFragment);
+                transaction.hide(mGroupDetailFragment);
+            }
+            transaction.commit();
+            fragmentManager.executePendingTransactions();
+
+            // These operations below are only okay if the fragment is already created.
+            // Because we create the fragment dynamically on 1-pane, this has to be done after
+            // the fragment transaction is executed.
+            mFavoritesFragment.setQuickContact(PhoneCapabilityTester.isUsingTwoPanes(this));
+            mFavoritesFragment.setDisplayType(DisplayType.STARRED_ONLY);
+        }
+
         setTitle(mRequest.getActivityTitle());
-        ActionBar actionBar = getActionBar();
-        mActionBarAdapter = new ActionBarAdapter(this, this);
-        mActionBarAdapter.onCreate(savedState, mRequest, getActionBar());
+        if (createContentView) {
+            mActionBarAdapter = new ActionBarAdapter(this, this, getActionBar());
+        }
+        mActionBarAdapter.initialize(savedState, mRequest);
+
 
         ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
         ContactDetailTabCarousel tabCarousel = (ContactDetailTabCarousel)
@@ -331,120 +355,15 @@
                 mContactDetailFragmentListener);
 
         if (createContentView) {
-            actionBar.removeAllTabs();
-            Tab favoritesTab = actionBar.newTab();
-            favoritesTab.setTag(TabState.FAVORITES);
-            favoritesTab.setText(getString(R.string.contactsFavoritesLabel));
-            favoritesTab.setTabListener(mTabListener);
-            actionBar.addTab(favoritesTab);
-
-            Tab allTab = actionBar.newTab();
-            allTab.setTag(TabState.ALL);
-            allTab.setText(getString(R.string.contactsAllLabel));
-            allTab.setTabListener(mTabListener);
-            actionBar.addTab(allTab);
-
-            Tab groupsTab = actionBar.newTab();
-            groupsTab.setTag(TabState.GROUPS);
-            groupsTab.setText(getString(R.string.contactsGroupsLabel));
-            groupsTab.setTabListener(mTabListener);
-            actionBar.addTab(groupsTab);
-            actionBar.setDisplayShowTitleEnabled(true);
-
-            TypedArray a = obtainStyledAttributes(null, R.styleable.ActionBarHomeIcon);
-            boolean showHomeIcon = a.getBoolean(R.styleable.ActionBarHomeIcon_show_home_icon, true);
-            actionBar.setDisplayShowHomeEnabled(showHomeIcon);
-
+            // TODO Is the createContentView test really necessary?
             invalidateOptionsMenuIfNeeded();
         }
 
         configureFragments(savedState == null);
     }
 
-    private void hideFragmentOnTabUnselect(TabState newTabState, FragmentTransaction ft) {
-        switch (newTabState) {
-            case FAVORITES: {
-                ft.hide(mFavoritesFragment);
-                if (mFrequentFragment != null) {
-                    ft.hide(mFrequentFragment);
-                }
-                break;
-            }
-            case ALL: {
-                ft.hide(mAllFragment);
-                if (mContactDetailFragment != null) {
-                    ft.hide(mContactDetailFragment);
-                }
-                break;
-            }
-            case GROUPS: {
-                ft.hide(mGroupsFragment);
-                if (mGroupDetailFragment != null) {
-                    ft.hide(mGroupDetailFragment);
-                }
-                break;
-            }
-            default: {
-                throw new IllegalStateException("Unexpected tab state: " + newTabState);
-            }
-        }
-    }
-
-    private void showFragmentOnTabSelect(TabState newTabState, FragmentTransaction ft) {
-        switch (newTabState) {
-            case FAVORITES: {
-                ft.show(mFavoritesFragment);
-                if (mFrequentFragment != null) {
-                    ft.show(mFrequentFragment);
-                }
-                break;
-            }
-            case ALL: {
-                ft.show(mAllFragment);
-                if (mContactDetailFragment != null) {
-                    ft.show(mContactDetailFragment);
-                }
-                break;
-            }
-            case GROUPS: {
-                ft.show(mGroupsFragment);
-                if (mGroupDetailFragment != null) {
-                    ft.show(mGroupDetailFragment);
-                }
-                break;
-            }
-            default: {
-                throw new IllegalStateException("Unexpected tab state: " + newTabState);
-            }
-        }
-    }
-
-    private void setSelectedTab(TabState tab) {
-        mSelectedTab = tab;
-
-        if (PhoneCapabilityTester.isUsingTwoPanes(this)) {
-            switch (mSelectedTab) {
-                case FAVORITES:
-                    mFavoritesView.setVisibility(View.VISIBLE);
-                    mBrowserView.setVisibility(View.GONE);
-                    mDetailsView.setVisibility(View.GONE);
-                    break;
-                case GROUPS:
-                case ALL:
-                    mFavoritesView.setVisibility(View.GONE);
-                    mBrowserView.setVisibility(View.VISIBLE);
-                    mDetailsView.setVisibility(View.VISIBLE);
-                    break;
-            }
-        }
-    }
-
     @Override
     protected void onPause() {
-        if (mActionBarAdapter != null) {
-            mActionBarAdapter.setListener(null);
-        }
-
         mOptionsMenuContactsAvailable = false;
 
         mProviderStatus = -1;
@@ -455,11 +374,12 @@
     @Override
     protected void onResume() {
         super.onResume();
-        if (mActionBarAdapter != null) {
-            mActionBarAdapter.setListener(this);
-        }
         mProviderStatusLoader.setProviderStatusListener(this);
-        updateFragmentVisibility();
+        showContactsUnavailableFragmentIfNecessary();
+
+        // Re-register the listener, which may have been cleared when onSaveInstanceState was
+        // called.  See also: onSaveInstanceState
+        mActionBarAdapter.setListener(this);
     }
 
     @Override
@@ -468,6 +388,12 @@
         super.onStart();
     }
 
+    @Override
+    protected void onDestroy() {
+        mActionBarAdapter.setListener(null);
+        super.onDestroy();
+    }
+
     private void configureFragments(boolean fromRequest) {
         if (fromRequest) {
             ContactListFilter filter = null;
@@ -492,7 +418,7 @@
                     break;
                 case ContactsRequest.ACTION_VIEW_CONTACT:
                     if (PhoneCapabilityTester.isUsingTwoPanes(this)) {
-                        getActionBar().setSelectedNavigationItem(TabState.ALL.ordinal());
+                        mActionBarAdapter.setCurrentTab(TabState.ALL);
                     }
             }
 
@@ -551,33 +477,14 @@
     public void onAction(Action action) {
         switch (action) {
             case START_SEARCH_MODE:
-                // Checking if multi fragments are being displayed
-                if (PhoneCapabilityTester.isUsingTwoPanes(this)) {
-                    mFavoritesView.setVisibility(View.GONE);
-                    mBrowserView.setVisibility(View.VISIBLE);
-                    mDetailsView.setVisibility(View.VISIBLE);
-                }
-                // Bring the contact list fragment (and detail fragment if applicable) to the front
-                FragmentTransaction ft = getFragmentManager().beginTransaction();
-                ft.show(mAllFragment);
-                if (mContactDetailFragment != null) ft.show(mContactDetailFragment);
-                ft.commit();
                 clearSearch();
+                updateFragmentsVisibility();
+                invalidateOptionsMenu();
                 break;
             case STOP_SEARCH_MODE:
-                // Refresh the fragments because search mode was using them to display search
-                // results.
                 clearSearch();
-
-                // If the last selected tab was not the "All contacts" tab, then hide these
-                // fragments because we need to show favorites or groups.
-                if (mSelectedTab != null && !mSelectedTab.equals(TabState.ALL)) {
-                    FragmentTransaction transaction = getFragmentManager().beginTransaction();
-                    transaction.hide(mAllFragment);
-                    if (mContactDetailFragment != null) transaction.hide(mContactDetailFragment);
-                    transaction.commit();
-                }
-                if (mSelectedTab != null) setSelectedTab(mSelectedTab);
+                updateFragmentsVisibility();
+                invalidateOptionsMenu();
                 break;
             case CHANGE_SEARCH_QUERY:
                 loadSearch(mActionBarAdapter.getQueryString());
@@ -587,6 +494,228 @@
         }
     }
 
+    @Override
+    public void onSelectedTabChanged() {
+        updateFragmentsVisibility();
+    }
+
+    /**
+     * Updates the fragment/view visibility according to the current mode, such as
+     * {@link ActionBarAdapter#isSearchMode()} and {@link ActionBarAdapter#getCurrentTab()}.
+     */
+    private void updateFragmentsVisibility() {
+        TabState tab = mActionBarAdapter.getCurrentTab();
+
+        // We use ViewPager on 1-pane.
+        if (!PhoneCapabilityTester.isUsingTwoPanes(this)) {
+            if (mActionBarAdapter.isSearchMode()) {
+                mTabPagerAdapter.setSearchMode(true);
+            } else {
+                mTabPagerAdapter.setSearchMode(false);
+                int tabIndex = tab.ordinal();
+                if (mTabPager.getCurrentItem() != tabIndex) {
+                    mTabPager.setCurrentItem(tab.ordinal(), false /* no smooth scroll */);
+                }
+            }
+            invalidateOptionsMenu();
+            return;
+        }
+
+        // for the tablet...
+
+        // If in search mode, we use the all list + contact details to show the result.
+        if (mActionBarAdapter.isSearchMode()) {
+            tab = TabState.ALL;
+        }
+        switch (tab) {
+            case FAVORITES:
+                mFavoritesView.setVisibility(View.VISIBLE);
+                mBrowserView.setVisibility(View.GONE);
+                mDetailsView.setVisibility(View.GONE);
+                break;
+            case GROUPS:
+            case ALL:
+                mFavoritesView.setVisibility(View.GONE);
+                mBrowserView.setVisibility(View.VISIBLE);
+                mDetailsView.setVisibility(View.VISIBLE);
+                break;
+        }
+        FragmentManager fragmentManager = getFragmentManager();
+        FragmentTransaction ft = fragmentManager.beginTransaction();
+
+        switch (tab) {
+            case FAVORITES:
+                showFragment(ft, mFavoritesFragment);
+                showFragment(ft, mFrequentFragment);
+                hideFragment(ft, mAllFragment);
+                hideFragment(ft, mContactDetailFragment);
+                hideFragment(ft, mGroupsFragment);
+                hideFragment(ft, mGroupDetailFragment);
+                break;
+            case ALL:
+                hideFragment(ft, mFavoritesFragment);
+                hideFragment(ft, mFrequentFragment);
+                showFragment(ft, mAllFragment);
+                showFragment(ft, mContactDetailFragment);
+                hideFragment(ft, mGroupsFragment);
+                hideFragment(ft, mGroupDetailFragment);
+                break;
+            case GROUPS:
+                hideFragment(ft, mFavoritesFragment);
+                hideFragment(ft, mFrequentFragment);
+                hideFragment(ft, mAllFragment);
+                hideFragment(ft, mContactDetailFragment);
+                showFragment(ft, mGroupsFragment);
+                showFragment(ft, mGroupDetailFragment);
+                break;
+        }
+        if (!ft.isEmpty()) {
+            ft.commit();
+            fragmentManager.executePendingTransactions();
+        }
+        invalidateOptionsMenu();
+    }
+
+    private class TabPagerListener implements ViewPager.OnPageChangeListener {
+        @Override
+        public void onPageScrollStateChanged(int state) {
+        }
+
+        @Override
+        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+        }
+
+        @Override
+        public void onPageSelected(int position) {
+            // Make sure not in the search mode, in which case position != TabState.ordinal().
+            if (!mTabPagerAdapter.isSearchMode()) {
+                mActionBarAdapter.setCurrentTab(TabState.fromInt(position), false);
+                invalidateOptionsMenu();
+            }
+        }
+    }
+
+    /**
+     * Adapter for the {@link ViewPager}.  Unlike {@link FragmentPagerAdapter},
+     * {@link #instantiateItem} returns existing fragments, and {@link #instantiateItem}/
+     * {@link #destroyItem} show/hide fragments instead of attaching/detaching.
+     *
+     * In search mode, we always show the "all" fragment, and disable the swipe.  We change the
+     * number of items to 1 to disable the swipe.
+     *
+     * TODO figure out a more straight way to disable swipe.
+     */
+    private class TabPagerAdapter extends PagerAdapter {
+        private final FragmentManager mFragmentManager;
+        private FragmentTransaction mCurTransaction = null;
+
+        private boolean mTabPagerAdapterSearchMode;
+
+        public TabPagerAdapter() {
+            mFragmentManager = getFragmentManager();
+        }
+
+        public boolean isSearchMode() {
+            return mTabPagerAdapterSearchMode;
+        }
+
+        public void setSearchMode(boolean searchMode) {
+            if (searchMode == mTabPagerAdapterSearchMode) {
+                return;
+            }
+            mTabPagerAdapterSearchMode = searchMode;
+            notifyDataSetChanged();
+        }
+
+        @Override
+        public int getCount() {
+            return mTabPagerAdapterSearchMode ? 1 : TabState.values().length;
+        }
+
+        /** Gets called when the number of items changes. */
+        @Override
+        public int getItemPosition(Object object) {
+            if (mTabPagerAdapterSearchMode) {
+                if (object == mAllFragment) {
+                    return 0; // Only 1 page in search mode
+                }
+            } else {
+                if (object == mFavoritesFragment) {
+                    return TabState.FAVORITES.ordinal();
+                }
+                if (object == mAllFragment) {
+                    return TabState.ALL.ordinal();
+                }
+                if (object == mGroupsFragment) {
+                    return TabState.GROUPS.ordinal();
+                }
+            }
+            return POSITION_NONE;
+        }
+
+        @Override
+        public void startUpdate(View container) {
+        }
+
+        private Fragment getFragment(int position) {
+            if (mTabPagerAdapterSearchMode) {
+                if (position == 0) {
+                    return mAllFragment;
+                }
+            } else {
+                if (position == TabState.FAVORITES.ordinal()) {
+                    return mFavoritesFragment;
+                } else if (position == TabState.ALL.ordinal()) {
+                    return mAllFragment;
+                } else if (position == TabState.GROUPS.ordinal()) {
+                    return mGroupsFragment;
+                }
+            }
+            throw new IllegalArgumentException("position: " + position);
+        }
+
+        @Override
+        public Object instantiateItem(View container, int position) {
+            if (mCurTransaction == null) {
+                mCurTransaction = mFragmentManager.beginTransaction();
+            }
+            Fragment f = getFragment(position);
+            mCurTransaction.show(f);
+            return f;
+        }
+
+        @Override
+        public void destroyItem(View container, int position, Object object) {
+            if (mCurTransaction == null) {
+                mCurTransaction = mFragmentManager.beginTransaction();
+            }
+            mCurTransaction.hide((Fragment) object);
+        }
+
+        @Override
+        public void finishUpdate(View container) {
+            if (mCurTransaction != null) {
+                mCurTransaction.commit();
+                mCurTransaction = null;
+                mFragmentManager.executePendingTransactions();
+            }
+        }
+
+        @Override
+        public boolean isViewFromObject(View view, Object object) {
+            return ((Fragment) object).getView() == view;
+        }
+
+        @Override
+        public Parcelable saveState() {
+            return null;
+        }
+
+        @Override
+        public void restoreState(Parcelable state, ClassLoader loader) {
+        }
+    }
+
     private void clearSearch() {
         loadSearch("");
     }
@@ -640,10 +769,10 @@
 
     @Override
     public void onProviderStatusChange() {
-        updateFragmentVisibility();
+        showContactsUnavailableFragmentIfNecessary();
     }
 
-    private void updateFragmentVisibility() {
+    private void showContactsUnavailableFragmentIfNecessary() {
         int providerStatus = mProviderStatusLoader.getProviderStatus();
         if (providerStatus == mProviderStatus) {
             return;
@@ -912,6 +1041,12 @@
             intent.setAction(Intent.ACTION_EDIT);
             startActivityForResult(intent, SUBACTIVITY_EDIT_GROUP);
         }
+
+        @Override
+        public void onContactSelected(Uri contactUri) {
+            // Nothing needs to be done here because either quickcontact will be displayed
+            // or activity will take care of selection
+        }
     }
 
     public void startActivityAndForwardResult(final Intent intent) {
@@ -927,30 +1062,12 @@
     }
 
     @Override
-    public boolean onCreatePanelMenu(int featureId, Menu menu) {
-        // No menu if contacts are unavailable
-        if (!areContactsAvailable()) {
-            return false;
-        }
-
-        return super.onCreatePanelMenu(featureId, menu);
-    }
-
-    @Override
-    public boolean onPreparePanel(int featureId, View view, Menu menu) {
-        // No menu if contacts are unavailable
-        if (!areContactsAvailable()) {
-            return false;
-        }
-
-        return super.onPreparePanel(featureId, view, menu);
-    }
-
-    @Override
     public boolean onCreateOptionsMenu(Menu menu) {
-        if (!areContactsAvailable()) {
-            return false;
-        }
+//      STOPSHIP Un-comment it once b/5027071 is fixed.
+//        if (!areContactsAvailable()) {
+//            If contacts aren't available, hide all menu items.
+//            return false;
+//        }
         super.onCreateOptionsMenu(menu);
 
         MenuInflater inflater = getMenuInflater();
@@ -1006,8 +1123,12 @@
     public boolean onPrepareOptionsMenu(Menu menu) {
         mOptionsMenuContactsAvailable = areContactsAvailable();
         if (!mOptionsMenuContactsAvailable) {
+            // STOPSHIP Remove makeAllMenuItemsVisible()when STOPSHIP in onCreateOptionsMenu() is
+            // fixed.
+            makeAllMenuItemsVisible(menu, false);
             return false;
         }
+        makeAllMenuItemsVisible(menu, true);
 
         final MenuItem searchMenu = menu.findItem(R.id.menu_search);
         final MenuItem addContactMenu = menu.findItem(R.id.menu_add_contact);
@@ -1019,11 +1140,8 @@
         if (mActionBarAdapter.isSearchMode()) {
             addContactMenu.setVisible(false);
             addGroupMenu.setVisible(false);
-            if (searchMenu != null) {
-                searchMenu.setVisible(false); // Don't show the search menu in search mode.
-            }
         } else {
-            switch (mSelectedTab) {
+            switch (mActionBarAdapter.getCurrentTab()) {
                 case FAVORITES:
                     // TODO: Fall through until we determine what the menu items should be for
                     // this tab
@@ -1038,6 +1156,11 @@
             }
         }
 
+        if (searchMenu != null) {
+            // Don't show the search menu in search mode.
+            searchMenu.setVisible(!mActionBarAdapter.isSearchMode());
+        }
+
         MenuItem settings = menu.findItem(R.id.menu_settings);
         if (settings != null) {
             settings.setVisible(!ContactsPreferenceActivity.isEmpty(this));
@@ -1046,6 +1169,13 @@
         return true;
     }
 
+    private void makeAllMenuItemsVisible(Menu menu, boolean visible) {
+        final int itemCount = menu.size();
+        for (int i = 0; i < itemCount; i++) {
+            menu.getItem(i).setVisible(visible);
+        }
+    }
+
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
@@ -1195,16 +1325,6 @@
     }
 
     @Override
-    public boolean onContextItemSelected(MenuItem item) {
-        ContextMenuAdapter menuAdapter = mAllFragment.getContextMenuAdapter();
-        if (menuAdapter != null) {
-            return menuAdapter.onContextItemSelected(item);
-        }
-
-        return super.onContextItemSelected(item);
-    }
-
-    @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         // TODO move to the fragment
         switch (keyCode) {
@@ -1272,21 +1392,21 @@
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
         outState.putBoolean(KEY_SEARCH_MODE, mSearchMode);
-        if (mActionBarAdapter != null) {
-            mActionBarAdapter.onSaveInstanceState(outState);
-        }
+        mActionBarAdapter.onSaveInstanceState(outState);
         if (mContactDetailLayoutController != null) {
             mContactDetailLayoutController.onSaveInstanceState(outState);
         }
+
+        // Clear the listener to make sure we don't get callbacks after onSaveInstanceState,
+        // in order to avoid doing fragment transactions after it.
+        // TODO Figure out a better way to deal with the issue.
+        mActionBarAdapter.setListener(null);
     }
 
     @Override
     protected void onRestoreInstanceState(Bundle inState) {
         super.onRestoreInstanceState(inState);
         mSearchMode = inState.getBoolean(KEY_SEARCH_MODE);
-        if (mActionBarAdapter != null) {
-            mActionBarAdapter.onRestoreInstanceState(inState);
-        }
         if (mContactDetailLayoutController != null) {
             mContactDetailLayoutController.onRestoreInstanceState(inState);
         }
diff --git a/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java b/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java
new file mode 100644
index 0000000..82ac971
--- /dev/null
+++ b/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.calllog;
+
+import com.android.contacts.PhoneCallDetails;
+import com.android.contacts.R;
+
+import android.content.Context;
+import android.provider.CallLog.Calls;
+import android.text.format.DateUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+/**
+ * Adapter for a ListView containing history items from the details of a call.
+ */
+public class CallDetailHistoryAdapter extends BaseAdapter {
+    private final Context mContext;
+    private final LayoutInflater mLayoutInflater;
+    private final CallTypeHelper mCallTypeHelper;
+    private final PhoneCallDetails[] mPhoneCallDetails;
+
+    public CallDetailHistoryAdapter(Context context, LayoutInflater layoutInflater,
+            CallTypeHelper callTypeHelper, PhoneCallDetails[] phoneCallDetails) {
+        mContext = context;
+        mLayoutInflater = layoutInflater;
+        mCallTypeHelper = callTypeHelper;
+        mPhoneCallDetails = phoneCallDetails;
+    }
+
+    @Override
+    public int getCount() {
+        return mPhoneCallDetails.length;
+    }
+
+    @Override
+    public Object getItem(int position) {
+        return mPhoneCallDetails[position];
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return position;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        // Make sure we have a valid convertView to start with
+        if (convertView == null) {
+            convertView = mLayoutInflater.inflate(R.layout.call_detail_history_item, parent, false);
+        }
+
+        PhoneCallDetails details = mPhoneCallDetails[position];
+        ImageView callTypeIconView = (ImageView) convertView.findViewById(R.id.call_type_icon);
+        TextView callTypeTextView = (TextView) convertView.findViewById(R.id.call_type_text);
+        TextView numberView = (TextView) convertView.findViewById(R.id.number);
+        TextView dateView = (TextView) convertView.findViewById(R.id.date);
+        TextView durationView = (TextView) convertView.findViewById(R.id.duration);
+
+        int callType = details.callTypes[0];
+        callTypeIconView.setImageDrawable(mCallTypeHelper.getCallTypeDrawable(callType));
+        callTypeTextView.setText(mCallTypeHelper.getCallTypeText(callType));
+        // TODO: Add the label for this number as well.
+        numberView.setText(details.number);
+        // Set the date.
+        CharSequence dateValue = DateUtils.formatDateRange(mContext, details.date, details.date,
+                DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE |
+                DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_SHOW_YEAR);
+        dateView.setText(dateValue);
+        // Set the duration
+        if (callType == Calls.MISSED_TYPE) {
+            durationView.setVisibility(View.GONE);
+        } else {
+            durationView.setVisibility(View.VISIBLE);
+            durationView.setText(formatDuration(details.duration));
+        }
+
+        return convertView;
+    }
+
+    private String formatDuration(long elapsedSeconds) {
+        long minutes = 0;
+        long seconds = 0;
+
+        if (elapsedSeconds >= 60) {
+            minutes = elapsedSeconds / 60;
+            elapsedSeconds -= minutes * 60;
+        }
+        seconds = elapsedSeconds;
+
+        return mContext.getString(R.string.callDetailsDurationFormat, minutes, seconds);
+    }
+}
diff --git a/src/com/android/contacts/calllog/CallLogFragment.java b/src/com/android/contacts/calllog/CallLogFragment.java
index 11f8965..90e405a 100644
--- a/src/com/android/contacts/calllog/CallLogFragment.java
+++ b/src/com/android/contacts/calllog/CallLogFragment.java
@@ -35,6 +35,7 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.database.CharArrayBuffer;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabaseCorruptException;
@@ -51,23 +52,18 @@
 import android.provider.ContactsContract.CommonDataKinds.SipAddress;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.Intents.Insert;
 import android.provider.ContactsContract.PhoneLookup;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
-import android.widget.AdapterView;
 import android.widget.ListView;
 import android.widget.QuickContactBadge;
 
@@ -77,13 +73,10 @@
 /**
  * Displays a list of call log entries.
  */
-public class CallLogFragment extends ListFragment
-        implements View.OnCreateContextMenuListener, ViewPagerVisibilityListener {
+public class CallLogFragment extends ListFragment implements ViewPagerVisibilityListener {
     private static final String TAG = "CallLogFragment";
 
-    /**
-     * The size of the cache of contact info.
-     */
+    /** The size of the cache of contact info. */
     private static final int CONTACT_INFO_CACHE_SIZE = 100;
 
     /** The query for the call log table */
@@ -126,10 +119,6 @@
         public static final int LOOKUP_KEY = 7;
     }
 
-    private static final class MenuItems {
-        public static final int DELETE = 1;
-    }
-
     private static final class OptionsMenuItems {
         public static final int DELETE_ALL = 1;
     }
@@ -261,25 +250,24 @@
             mRequests = new LinkedList<CallerInfoQuery>();
             mPreDrawListener = null;
 
-            Drawable incomingDrawable = getResources().getDrawable(
-                    R.drawable.ic_call_log_list_incoming_call);
-            Drawable outgoingDrawable = getResources().getDrawable(
-                    R.drawable.ic_call_log_list_outgoing_call);
-            Drawable missedDrawable = getResources().getDrawable(
-                    R.drawable.ic_call_log_list_missed_call);
-            Drawable voicemailDrawable = getResources().getDrawable(
-                    R.drawable.ic_call_log_list_voicemail);
-            Drawable callDrawable = getResources().getDrawable(
+            Resources resources = getResources();
+            CallTypeHelper callTypeHelper = new CallTypeHelper(resources,
+                    resources.getDrawable(R.drawable.ic_call_incoming_holo_dark),
+                    resources.getDrawable(R.drawable.ic_call_outgoing_holo_dark),
+                    resources.getDrawable(R.drawable.ic_call_missed_holo_dark),
+                    resources.getDrawable(R.drawable.ic_call_voicemail_holo_dark));
+            Drawable callDrawable = resources.getDrawable(
                     R.drawable.ic_call_log_list_action_call);
-            Drawable playDrawable = getResources().getDrawable(
+            Drawable playDrawable = resources.getDrawable(
                     R.drawable.ic_call_log_list_action_play);
 
             mContactPhotoManager = ContactPhotoManager.getInstance(getActivity());
+            PhoneNumberHelper phoneNumberHelper =
+                    new PhoneNumberHelper(getResources(), mVoiceMailNumber);
             PhoneCallDetailsHelper phoneCallDetailsHelper = new PhoneCallDetailsHelper(
-                    getActivity(), getResources(), mVoiceMailNumber, incomingDrawable,
-                    outgoingDrawable, missedDrawable, voicemailDrawable);
-            mCallLogViewsHelper = new CallLogListItemHelper(phoneCallDetailsHelper, callDrawable,
-                    playDrawable);
+                    getActivity(), resources, callTypeHelper, phoneNumberHelper );
+            mCallLogViewsHelper = new CallLogListItemHelper(phoneCallDetailsHelper,
+                    phoneNumberHelper, callDrawable, playDrawable);
         }
 
         /**
@@ -640,6 +628,7 @@
 
             String number = c.getString(CallLogQuery.NUMBER);
             long date = c.getLong(CallLogQuery.DATE);
+            long duration = c.getLong(CallLogQuery.DURATION);
             final String formattedNumber;
             String countryIso = c.getString(CallLogQuery.COUNTRY_ISO);
             // Store away the number so we can call it directly if you click on the call icon
@@ -684,7 +673,7 @@
                 formattedNumber = formatPhoneNumber(number, null, countryIso);
             }
 
-            long contactId = info.personId;
+            long personId = info.personId;
             String name = info.name;
             int ntype = info.type;
             String label = info.label;
@@ -699,14 +688,14 @@
             int[] callTypes = getCallTypes(c, count);
             final PhoneCallDetails details;
             if (TextUtils.isEmpty(name)) {
-                details = new PhoneCallDetails(number, formattedNumber, callTypes, date);
+                details = new PhoneCallDetails(number, formattedNumber, callTypes, date, duration);
             } else {
-                details = new PhoneCallDetails(number, formattedNumber, callTypes, date, name,
-                        ntype, label);
+                details = new PhoneCallDetails(number, formattedNumber, callTypes, date, duration,
+                        name, ntype, label, personId, photoId);
             }
             mCallLogViewsHelper.setPhoneCallDetails(views, details , true);
             if (views.photoView != null) {
-                bindQuickContact(views.photoView, photoId, contactId, lookupKey);
+                bindQuickContact(views.photoView, photoId, personId, lookupKey);
             }
 
 
@@ -842,7 +831,6 @@
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
-        getListView().setOnCreateContextMenuListener(this);
         mAdapter = new CallLogAdapter();
         setListAdapter(mAdapter);
     }
@@ -949,88 +937,6 @@
     }
 
     @Override
-    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfoIn) {
-        AdapterView.AdapterContextMenuInfo menuInfo;
-        try {
-             menuInfo = (AdapterView.AdapterContextMenuInfo) menuInfoIn;
-        } catch (ClassCastException e) {
-            Log.e(TAG, "bad menuInfoIn", e);
-            return;
-        }
-
-        Cursor cursor = (Cursor) mAdapter.getItem(menuInfo.position);
-
-        String number = cursor.getString(CallLogQuery.NUMBER);
-        Uri numberUri = null;
-        boolean isVoicemail = false;
-        boolean isSipNumber = false;
-        if (number.equals(CallerInfo.UNKNOWN_NUMBER)) {
-            number = getString(R.string.unknown);
-        } else if (number.equals(CallerInfo.PRIVATE_NUMBER)) {
-            number = getString(R.string.private_num);
-        } else if (number.equals(CallerInfo.PAYPHONE_NUMBER)) {
-            number = getString(R.string.payphone);
-        } else if (PhoneNumberUtils.extractNetworkPortion(number).equals(mVoiceMailNumber)) {
-            number = getString(R.string.voicemail);
-            numberUri = Uri.parse("voicemail:x");
-            isVoicemail = true;
-        } else if (PhoneNumberUtils.isUriNumber(number)) {
-            numberUri = Uri.fromParts("sip", number, null);
-            isSipNumber = true;
-        } else {
-            numberUri = Uri.fromParts("tel", number, null);
-        }
-
-        ContactInfo info = mAdapter.getContactInfo(number);
-        boolean contactInfoPresent = (info != null && info != ContactInfo.EMPTY);
-        if (contactInfoPresent) {
-            menu.setHeaderTitle(info.name);
-        } else {
-            menu.setHeaderTitle(number);
-        }
-
-        if (numberUri != null) {
-            Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, numberUri);
-            menu.add(0, 0, 0, getResources().getString(R.string.recentCalls_callNumber, number))
-                    .setIntent(intent);
-        }
-
-        if (contactInfoPresent) {
-            menu.add(0, 0, 0, R.string.menu_viewContact)
-                    .setIntent(new Intent(Intent.ACTION_VIEW,
-                            ContentUris.withAppendedId(Contacts.CONTENT_URI, info.personId)));
-        }
-
-        if (numberUri != null && !isVoicemail && !isSipNumber) {
-            menu.add(0, 0, 0, R.string.recentCalls_editNumberBeforeCall)
-                    .setIntent(new Intent(Intent.ACTION_DIAL, numberUri));
-            menu.add(0, 0, 0, R.string.menu_sendTextMessage)
-                    .setIntent(new Intent(Intent.ACTION_SENDTO,
-                            Uri.fromParts("sms", number, null)));
-        }
-
-        // "Add to contacts" item, if this entry isn't already associated with a contact
-        if (!contactInfoPresent && numberUri != null && !isVoicemail && !isSipNumber) {
-            // TODO: This item is currently disabled for SIP addresses, because
-            // the Insert.PHONE extra only works correctly for PSTN numbers.
-            //
-            // To fix this for SIP addresses, we need to:
-            // - define ContactsContract.Intents.Insert.SIP_ADDRESS, and use it here if
-            //   the current number is a SIP address
-            // - update the contacts UI code to handle Insert.SIP_ADDRESS by
-            //   updating the SipAddress field
-            // and then we can remove the "!isSipNumber" check above.
-
-            Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
-            intent.setType(Contacts.CONTENT_ITEM_TYPE);
-            intent.putExtra(Insert.PHONE, number);
-            menu.add(0, 0, 0, R.string.recentCalls_addToContact)
-                    .setIntent(intent);
-        }
-        menu.add(0, MenuItems.DELETE, 0, R.string.recentCalls_removeFromRecentList);
-    }
-
-    @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
             case OptionsMenuItems.DELETE_ALL: {
@@ -1041,42 +947,6 @@
         return super.onOptionsItemSelected(item);
     }
 
-    @Override
-    public boolean onContextItemSelected(MenuItem item) {
-        // Convert the menu info to the proper type
-        AdapterView.AdapterContextMenuInfo menuInfo;
-        try {
-             menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
-        } catch (ClassCastException e) {
-            Log.e(TAG, "bad menuInfoIn", e);
-            return false;
-        }
-
-        switch (item.getItemId()) {
-            case MenuItems.DELETE: {
-                Cursor cursor = (Cursor)mAdapter.getItem(menuInfo.position);
-                int groupSize = 1;
-                if (mAdapter.isGroupHeader(menuInfo.position)) {
-                    groupSize = mAdapter.getGroupSize(menuInfo.position);
-                }
-
-                StringBuilder sb = new StringBuilder();
-                for (int i = 0; i < groupSize; i++) {
-                    if (i != 0) {
-                        sb.append(",");
-                        cursor.moveToNext();
-                    }
-                    long id = cursor.getLong(CallLogQuery.ID);
-                    sb.append(id);
-                }
-
-                getActivity().getContentResolver().delete(Calls.CONTENT_URI_WITH_VOICEMAIL,
-                        Calls._ID + " IN (" + sb + ")", null);
-            }
-        }
-        return super.onContextItemSelected(item);
-    }
-
     /*
      * Get the number from the Contacts, if available, since sometimes
      * the number provided by caller id may not be formatted properly
@@ -1159,13 +1029,25 @@
 
     @Override
     public void onListItemClick(ListView l, View v, int position, long id) {
+        Intent intent = new Intent(getActivity(), CallDetailActivity.class);
         if (mAdapter.isGroupHeader(position)) {
-            mAdapter.toggleGroup(position);
+            int groupSize = mAdapter.getGroupSize(position);
+            long[] ids = new long[groupSize];
+            // Copy the ids of the rows in the group.
+            Cursor cursor = (Cursor) mAdapter.getItem(position);
+            // Restore the position in the cursor at the end.
+            int currentPosition = cursor.getPosition();
+            for (int index = 0; index < groupSize; ++index) {
+                ids[index] = cursor.getLong(CallLogQuery.ID);
+                cursor.moveToNext();
+            }
+            cursor.moveToPosition(currentPosition);
+            intent.putExtra(CallDetailActivity.EXTRA_CALL_LOG_IDS, ids);
         } else {
-            Intent intent = new Intent(getActivity(), CallDetailActivity.class);
+            // If there is a single item, use the direct URI for it.
             intent.setData(ContentUris.withAppendedId(Calls.CONTENT_URI_WITH_VOICEMAIL, id));
-            startActivity(intent);
         }
+        startActivity(intent);
     }
 
     @VisibleForTesting
diff --git a/src/com/android/contacts/calllog/CallLogListItemHelper.java b/src/com/android/contacts/calllog/CallLogListItemHelper.java
index e4630e9..a8894da 100644
--- a/src/com/android/contacts/calllog/CallLogListItemHelper.java
+++ b/src/com/android/contacts/calllog/CallLogListItemHelper.java
@@ -18,11 +18,9 @@
 
 import com.android.contacts.PhoneCallDetails;
 import com.android.contacts.PhoneCallDetailsHelper;
-import com.android.internal.telephony.CallerInfo;
 
 import android.graphics.drawable.Drawable;
 import android.provider.CallLog.Calls;
-import android.text.TextUtils;
 import android.view.View;
 
 /**
@@ -31,6 +29,8 @@
 /*package*/ class CallLogListItemHelper {
     /** Helper for populating the details of a phone call. */
     private final PhoneCallDetailsHelper mPhoneCallDetailsHelper;
+    /** Helper for handling phone numbers. */
+    private final PhoneNumberHelper mPhoneNumberHelper;
     /** Icon for the call action. */
     private final Drawable mCallDrawable;
     /** Icon for the play action. */
@@ -44,8 +44,9 @@
      * @param playDrawable used to render the play button, for playing a voicemail
      */
     public CallLogListItemHelper(PhoneCallDetailsHelper phoneCallDetailsHelper,
-            Drawable callDrawable, Drawable playDrawable) {
+            PhoneNumberHelper phoneNumberHelper, Drawable callDrawable, Drawable playDrawable) {
         mPhoneCallDetailsHelper = phoneCallDetailsHelper;
+        mPhoneNumberHelper= phoneNumberHelper;
         mCallDrawable = callDrawable;
         mPlayDrawable = playDrawable;
     }
@@ -65,15 +66,8 @@
             views.callView.setImageDrawable(
                     details.callTypes[0] == Calls.VOICEMAIL_TYPE ? mPlayDrawable : mCallDrawable);
             views.callView.setVisibility(
-                    canPlaceCallsTo(details.number) ? View.VISIBLE : View.INVISIBLE);
+                    mPhoneNumberHelper.canPlaceCallsTo(details.number)
+                            ? View.VISIBLE : View.INVISIBLE);
         }
     }
-
-    /** Returns true if it is possible to place a call to the given number. */
-    public boolean canPlaceCallsTo(CharSequence number) {
-        return !(TextUtils.isEmpty(number)
-                || number.equals(CallerInfo.UNKNOWN_NUMBER)
-                || number.equals(CallerInfo.PRIVATE_NUMBER)
-                || number.equals(CallerInfo.PAYPHONE_NUMBER));
-    }
 }
diff --git a/src/com/android/contacts/calllog/CallTypeHelper.java b/src/com/android/contacts/calllog/CallTypeHelper.java
new file mode 100644
index 0000000..b06a1c1
--- /dev/null
+++ b/src/com/android/contacts/calllog/CallTypeHelper.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.calllog;
+
+import com.android.contacts.R;
+
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.provider.CallLog.Calls;
+
+/**
+ * Helper class to perform operations related to call types.
+ */
+public class CallTypeHelper {
+    /** Icon for incoming calls. */
+    private final Drawable mIncomingDrawable;
+    /** Icon for outgoing calls. */
+    private final Drawable mOutgoingDrawable;
+    /** Icon for missed calls. */
+    private final Drawable mMissedDrawable;
+    /** Icon for voicemails. */
+    private final Drawable mVoicemailDrawable;
+    /** Name used to identify incoming calls. */
+    private final String mIncomingName;
+    /** Name used to identify outgoing calls. */
+    private final String mOutgoingName;
+    /** Name used to identify missed calls. */
+    private final String mMissedName;
+    /** Name used to identify voicemail calls. */
+    private final String mVoicemailName;
+
+    public CallTypeHelper(Resources resources, Drawable incomingDrawable, Drawable outgoingDrawable,
+            Drawable missedDrawable, Drawable voicemailDrawable) {
+        mIncomingDrawable = incomingDrawable;
+        mOutgoingDrawable = outgoingDrawable;
+        mMissedDrawable = missedDrawable;
+        mVoicemailDrawable = voicemailDrawable;
+        // Cache these values so that we do not need to look them up each time.
+        mIncomingName = resources.getString(R.string.type_incoming);
+        mOutgoingName = resources.getString(R.string.type_outgoing);
+        mMissedName = resources.getString(R.string.type_missed);
+        mVoicemailName = resources.getString(R.string.type_voicemail);
+    }
+
+    /** Returns the text used to represent the given call type. */
+    public String getCallTypeText(int callType) {
+        switch (callType) {
+            case Calls.INCOMING_TYPE:
+                return mIncomingName;
+
+            case Calls.OUTGOING_TYPE:
+                return mOutgoingName;
+
+            case Calls.MISSED_TYPE:
+                return mMissedName;
+
+            case Calls.VOICEMAIL_TYPE:
+                return mVoicemailName;
+
+            default:
+                throw new IllegalArgumentException("invalid call type: " + callType);
+        }
+    }
+
+    /** Returns the drawable of the icon associated with the given call type. */
+    public Drawable getCallTypeDrawable(int callType) {
+        switch (callType) {
+            case Calls.INCOMING_TYPE:
+                return mIncomingDrawable;
+
+            case Calls.OUTGOING_TYPE:
+                return mOutgoingDrawable;
+
+            case Calls.MISSED_TYPE:
+                return mMissedDrawable;
+
+            case Calls.VOICEMAIL_TYPE:
+                return mVoicemailDrawable;
+
+            default:
+                throw new IllegalArgumentException("invalid call type: " + callType);
+        }
+    }
+}
diff --git a/src/com/android/contacts/calllog/PhoneNumberHelper.java b/src/com/android/contacts/calllog/PhoneNumberHelper.java
new file mode 100644
index 0000000..4d96f4f
--- /dev/null
+++ b/src/com/android/contacts/calllog/PhoneNumberHelper.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.calllog;
+
+import com.android.contacts.R;
+import com.android.internal.telephony.CallerInfo;
+
+import android.content.res.Resources;
+import android.net.Uri;
+import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
+
+/**
+ * Helper for formatting and managing phone numbers.
+ */
+public class PhoneNumberHelper {
+    private final Resources mResources;
+    private final String mVoicemailNumber;
+
+    public PhoneNumberHelper(Resources resources, String voicemailNumber) {
+        mResources = resources;
+        mVoicemailNumber = voicemailNumber;
+    }
+
+    /** Returns true if it is possible to place a call to the given number. */
+    public boolean canPlaceCallsTo(CharSequence number) {
+        return !(TextUtils.isEmpty(number)
+                || number.equals(CallerInfo.UNKNOWN_NUMBER)
+                || number.equals(CallerInfo.PRIVATE_NUMBER)
+                || number.equals(CallerInfo.PAYPHONE_NUMBER));
+    }
+
+    /** Returns true if it is possible to send an SMS to the given number. */
+    public boolean canSendSmsTo(CharSequence number) {
+        return canPlaceCallsTo(number) && !isVoicemailNumber(number) && !isSipNumber(number);
+    }
+
+    /**
+     * Returns the string to display for the given phone number.
+     *
+     * @param number the number to display
+     * @param formattedNumber the formatted number if available, may be null
+     */
+    public CharSequence getDisplayNumber(CharSequence number, CharSequence formattedNumber) {
+        if (TextUtils.isEmpty(number)) {
+            return "";
+        }
+        if (number.equals(CallerInfo.UNKNOWN_NUMBER)) {
+            return mResources.getString(R.string.unknown);
+        }
+        if (number.equals(CallerInfo.PRIVATE_NUMBER)) {
+            return mResources.getString(R.string.private_num);
+        }
+        if (number.equals(CallerInfo.PAYPHONE_NUMBER)) {
+            return mResources.getString(R.string.payphone);
+        }
+        if (PhoneNumberUtils.extractNetworkPortion(number.toString()).equals(mVoicemailNumber)) {
+            return mResources.getString(R.string.voicemail);
+        }
+        if (TextUtils.isEmpty(formattedNumber)) {
+            return number;
+        } else {
+            return formattedNumber;
+        }
+    }
+
+    /** Returns a URI that can be used to place a call to this number. */
+    public Uri getCallUri(String number) {
+        if (isVoicemailNumber(number)) {
+            return Uri.parse("voicemail:x");
+        }
+        if (isSipNumber(number)) {
+             return Uri.fromParts("sip", number, null);
+        }
+         return Uri.fromParts("tel", number, null);
+     }
+
+    /** Returns true if the given number is the number of the configured voicemail. */
+    public boolean isVoicemailNumber(CharSequence number) {
+        return PhoneNumberUtils.extractNetworkPortion(number.toString()).equals(mVoicemailNumber);
+    }
+
+    /** Returns true if the given number is a SIP address. */
+    public boolean isSipNumber(CharSequence number) {
+        return PhoneNumberUtils.isUriNumber(number.toString());
+    }
+}
diff --git a/src/com/android/contacts/group/GroupDetailFragment.java b/src/com/android/contacts/group/GroupDetailFragment.java
index 55888aa..c5f6ef4 100644
--- a/src/com/android/contacts/group/GroupDetailFragment.java
+++ b/src/com/android/contacts/group/GroupDetailFragment.java
@@ -67,6 +67,11 @@
          * User decided to go to Edit-Mode
          */
         public void onEditRequested(Uri groupUri);
+
+        /**
+         * Contact is selected and should launch details page
+         */
+        public void onContactSelected(Uri contactUri);
     }
 
     private static final String TAG = "GroupDetailFragment";
@@ -180,7 +185,7 @@
 
         @Override
         public void onContactSelected(Uri contactUri) {
-            // TODO: Launch Quick Contact
+            mListener.onContactSelected(contactUri);
         }
     };
 
diff --git a/src/com/android/contacts/group/GroupEditorFragment.java b/src/com/android/contacts/group/GroupEditorFragment.java
index 07d19a7..429bb58 100644
--- a/src/com/android/contacts/group/GroupEditorFragment.java
+++ b/src/com/android/contacts/group/GroupEditorFragment.java
@@ -363,26 +363,6 @@
         mGroupNameView.setFocusable(!mGroupNameIsReadOnly);
         setupAccountHeader();
 
-        // Setup the group member suggestion adapter
-        mAutoCompleteAdapter = new SuggestedMemberListAdapter(getActivity(),
-                android.R.layout.simple_dropdown_item_1line);
-        mAutoCompleteAdapter.setContentResolver(mContentResolver);
-        mAutoCompleteAdapter.setAccountType(mAccountType);
-        mAutoCompleteAdapter.setAccountName(mAccountName);
-        mAutoCompleteTextView.setAdapter(mAutoCompleteAdapter);
-        mAutoCompleteTextView.setOnItemClickListener(new OnItemClickListener() {
-            @Override
-            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-                SuggestedMember member = mAutoCompleteAdapter.getItem(position);
-                loadMemberToAddToGroup(String.valueOf(member.getContactId()));
-
-                // Update the autocomplete adapter so the contact doesn't get suggested again
-                mAutoCompleteAdapter.addNewMember(member.getContactId());
-
-                // Clear out the text field
-                mAutoCompleteTextView.setText("");
-            }
-        });
     }
 
     public void loadMemberToAddToGroup(String contactId) {
@@ -630,8 +610,33 @@
             }
             // Update the list of displayed existing members
             mMemberListAdapter.updateExistingMembersList(listMembers);
+
+            // Setup the group member suggestion adapter
+            mAutoCompleteAdapter = new SuggestedMemberListAdapter(getActivity(),
+                    android.R.layout.simple_dropdown_item_1line);
+            mAutoCompleteAdapter.setContentResolver(mContentResolver);
+            mAutoCompleteAdapter.setAccountType(mAccountType);
+            mAutoCompleteAdapter.setAccountName(mAccountName);
+            mAutoCompleteTextView.setAdapter(mAutoCompleteAdapter);
+            mAutoCompleteTextView.setOnItemClickListener(new OnItemClickListener() {
+                @Override
+                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                    SuggestedMember member = mAutoCompleteAdapter.getItem(position);
+                    loadMemberToAddToGroup(String.valueOf(member.getContactId()));
+
+                    // Update the autocomplete adapter so the contact doesn't get suggested again
+                    mAutoCompleteAdapter.addNewMember(member.getContactId());
+
+                    // Clear out the text field
+                    mAutoCompleteTextView.setText("");
+                }
+            });
+
             // Update the autocomplete adapter
             mAutoCompleteAdapter.updateExistingMembersList(listContactIds);
+            // No more updates
+            // TODO: move to a runnable
+            getLoaderManager().destroyLoader(LOADER_EXISTING_MEMBERS);
         }
 
         @Override
diff --git a/src/com/android/contacts/list/ContactBrowseListContextMenuAdapter.java b/src/com/android/contacts/list/ContactBrowseListContextMenuAdapter.java
index f2a53ca..135fbc6 100644
--- a/src/com/android/contacts/list/ContactBrowseListContextMenuAdapter.java
+++ b/src/com/android/contacts/list/ContactBrowseListContextMenuAdapter.java
@@ -30,6 +30,8 @@
 
 /**
  * A contextual menu adapter for the basic contact list.
+ *
+ * TODO Not used any more.  Remove it.
  */
 public class ContactBrowseListContextMenuAdapter implements ContextMenuAdapter {
 
diff --git a/src/com/android/contacts/list/ContactTileAdapter.java b/src/com/android/contacts/list/ContactTileAdapter.java
index 20c639e..360c7a3 100644
--- a/src/com/android/contacts/list/ContactTileAdapter.java
+++ b/src/com/android/contacts/list/ContactTileAdapter.java
@@ -294,6 +294,7 @@
 
         switch (itemViewType) {
             case ViewTypes.STARRED:
+            case ViewTypes.STARRED_WITH_SECONDARY_ACTION:
                 if (contactTileRowView == null) {
                     // Creating new row if needed
                     contactTileRowView = new ContactTileRow(mContext, layoutResId, true);
@@ -336,6 +337,8 @@
                 }
             case ViewTypes.FREQUENT:
                 return R.layout.contact_tile_frequent;
+            case ViewTypes.STARRED_WITH_SECONDARY_ACTION:
+                return R.layout.contact_tile_starred_secondary_target;
             default:
                 throw new IllegalArgumentException("Received unrecognized viewType " + viewType);
         }
@@ -358,7 +361,7 @@
         switch (mDisplayType) {
             case STREQUENT:
                 if (position < mDividerRowIndex) {
-                    return ViewTypes.STARRED;
+                    return ViewTypes.STARRED_WITH_SECONDARY_ACTION;
                 } else if (position == mDividerRowIndex) {
                     return ViewTypes.DIVIDER;
                 } else {
@@ -405,7 +408,13 @@
 
             if (getChildCount() <= tileIndex) {
                 if (mIsContactTileSquare) {
-                    contactTile = (ContactTileStarredView) inflate(mContext, mLayoutResId, null);
+                    if (mDisplayType == DisplayType.STREQUENT) {
+                        contactTile = (ContactTileSecondaryTargetView)
+                                inflate(mContext, mLayoutResId, null);
+                    } else {
+                        contactTile =
+                                (ContactTileStarredView) inflate(mContext, mLayoutResId, null);
+                    }
                 } else {
                     contactTile = (ContactTileView) inflate(mContext, mLayoutResId, null);
                 }
@@ -437,10 +446,11 @@
     }
 
     private static class ViewTypes {
-        public static final int COUNT = 3;
+        public static final int COUNT = 4;
         public static final int STARRED = 0;
         public static final int DIVIDER = 1;
         public static final int FREQUENT = 2;
+        public static final int STARRED_WITH_SECONDARY_ACTION = 3;
     }
 
     public interface Listener {
diff --git a/src/com/android/contacts/list/ContactTileSecondaryTargetView.java b/src/com/android/contacts/list/ContactTileSecondaryTargetView.java
new file mode 100644
index 0000000..862e23d
--- /dev/null
+++ b/src/com/android/contacts/list/ContactTileSecondaryTargetView.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.contacts.list;
+
+import com.android.contacts.R;
+
+import android.content.Context;
+import android.content.Intent;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ImageButton;
+
+/**
+ * A {@link ContactTileSecondaryTargetView} displays the contact's picture overlayed with their name
+ * in a perfect square like the {@link ContactTileStarredView}. However it adds in an additional
+ * touch target for a secondary action.
+ */
+public class ContactTileSecondaryTargetView extends ContactTileStarredView
+        implements OnClickListener {
+
+    private final static String TAG = ContactTileSecondaryTargetView.class.getSimpleName();
+
+    private ImageButton mSecondaryButton;
+
+    public ContactTileSecondaryTargetView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mSecondaryButton = (ImageButton) findViewById(R.id.contact_tile_secondary_button);
+        mSecondaryButton.setOnClickListener(this);
+    }
+
+    @Override
+    public void onClick(View v) {
+        getContext().startActivity(new Intent(Intent.ACTION_VIEW, getLookupUri()));
+    }
+}
diff --git a/src/com/android/contacts/list/ContactTileView.java b/src/com/android/contacts/list/ContactTileView.java
index 279dc93..7981bd1 100644
--- a/src/com/android/contacts/list/ContactTileView.java
+++ b/src/com/android/contacts/list/ContactTileView.java
@@ -43,6 +43,7 @@
 
     public ContactTileView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        setLayerType(View.LAYER_TYPE_HARDWARE, null);
     }
 
     @Override
diff --git a/tests/res/values/donottranslate_strings.xml b/tests/res/values/donottranslate_strings.xml
index 6ba575a..9f9f5a4 100644
--- a/tests/res/values/donottranslate_strings.xml
+++ b/tests/res/values/donottranslate_strings.xml
@@ -82,6 +82,9 @@
         <item>DIAL tel</item>
         <item>VIEW tel</item>
         <item>VIEW calls (call-log after a phone call)</item>
+        <item>VIEW calls item</item>
+        <item>CallDetailActivity (legacy)</item>
+        <item>CallLogActivity (legacy)</item>
     </string-array>
 
     <string name="pinnedHeaderList">Pinned Headers</string>
diff --git a/tests/src/com/android/contacts/ContactLoaderTest.java b/tests/src/com/android/contacts/ContactLoaderTest.java
index d923bfa..1d3fb20 100644
--- a/tests/src/com/android/contacts/ContactLoaderTest.java
+++ b/tests/src/com/android/contacts/ContactLoaderTest.java
@@ -312,7 +312,7 @@
                         "mockAccountName", "mockAccountType", 0,
                         1, 0, "sync1",
                         "sync2", "sync3", "sync4",
-                        0, 0, 0,
+                        0, 0,
 
                         dataId,
 
diff --git a/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java b/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
index 353c2ec..4f95563 100644
--- a/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
+++ b/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
@@ -16,10 +16,13 @@
 
 package com.android.contacts;
 
+import com.android.contacts.calllog.CallTypeHelper;
+import com.android.contacts.calllog.PhoneNumberHelper;
 import com.android.contacts.util.LocaleTestUtils;
 import com.android.internal.telephony.CallerInfo;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -41,6 +44,8 @@
     private static final String TEST_VOICEMAIL_NUMBER = "125";
     /** The date of the call log entry. */
     private static final long TEST_DATE = 1300000000;
+    /** A test duration value for phone calls. */
+    private static final long TEST_DURATION = 62300;
     /** The number of the caller/callee in the log entry. */
     private static final String TEST_NUMBER = "14125555555";
     /** The formatted version of {@link #TEST_NUMBER}. */
@@ -63,9 +68,12 @@
     protected void setUp() throws Exception {
         super.setUp();
         Context context = getContext();
-        mHelper = new PhoneCallDetailsHelper(context, context.getResources(),
-                TEST_VOICEMAIL_NUMBER, TEST_INCOMING_DRAWABLE, TEST_OUTGOING_DRAWABLE,
-                TEST_MISSED_DRAWABLE, TEST_VOICEMAIL_DRAWABLE);
+        Resources resources = context.getResources();
+        CallTypeHelper callTypeHelper = new CallTypeHelper(resources, TEST_INCOMING_DRAWABLE,
+                TEST_OUTGOING_DRAWABLE, TEST_MISSED_DRAWABLE, TEST_VOICEMAIL_DRAWABLE);
+        PhoneNumberHelper phoneNumberHelper =
+                new PhoneNumberHelper(resources, TEST_VOICEMAIL_NUMBER);
+        mHelper = new PhoneCallDetailsHelper(context, resources, callTypeHelper, phoneNumberHelper);
         mViews = PhoneCallDetailsViews.createForTest(new TextView(context),
                 new LinearLayout(context), new TextView(context), new View(context),
                 new TextView(context), new TextView(context));
@@ -204,7 +212,7 @@
     private void setPhoneCallDetailsWithNumber(String number, String formattedNumber) {
         mHelper.setPhoneCallDetails(mViews,
                 new PhoneCallDetails(number, formattedNumber, new int[]{ Calls.INCOMING_TYPE },
-                        TEST_DATE),
+                        TEST_DATE, TEST_DURATION),
                 false);
     }
 
@@ -212,7 +220,7 @@
     private void setPhoneCallDetailsWithDate(long date) {
         mHelper.setPhoneCallDetails(mViews,
                 new PhoneCallDetails(TEST_NUMBER, TEST_FORMATTED_NUMBER,
-                        new int[]{ Calls.INCOMING_TYPE }, date),
+                        new int[]{ Calls.INCOMING_TYPE }, date, TEST_DURATION),
                 false);
     }
 
@@ -228,7 +236,8 @@
 
     private void setPhoneCallDetailsWithCallTypes(boolean useIcons, int... callTypes) {
         mHelper.setPhoneCallDetails(mViews,
-                new PhoneCallDetails(TEST_NUMBER, TEST_FORMATTED_NUMBER, callTypes, TEST_DATE),
+                new PhoneCallDetails(TEST_NUMBER, TEST_FORMATTED_NUMBER, callTypes, TEST_DATE,
+                        TEST_DURATION),
                 useIcons);
     }
 }
diff --git a/tests/src/com/android/contacts/activities/CallLogActivityTests.java b/tests/src/com/android/contacts/activities/CallLogActivityTests.java
index 8db291d..4004227 100644
--- a/tests/src/com/android/contacts/activities/CallLogActivityTests.java
+++ b/tests/src/com/android/contacts/activities/CallLogActivityTests.java
@@ -166,8 +166,7 @@
         insert(CallerInfo.PRIVATE_NUMBER, NOW, 0, Calls.INCOMING_TYPE);
         View view = mAdapter.newGroupView(getActivity(), mParentView);
         mAdapter.bindGroupView(view, getActivity(), mCursor, 3, false);
-        assertNull(view.findViewById(R.id.call_icon));
-        assertNotNull(view.findViewById(R.id.groupIndicator));
+        assertNotNull(view.findViewById(R.id.call_icon));
     }
 
     @MediumTest
@@ -321,9 +320,9 @@
     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"));
+        mCallTypeIcons.put(Calls.INCOMING_TYPE, getBitmap("ic_call_incoming_holo_dark"));
+        mCallTypeIcons.put(Calls.MISSED_TYPE, getBitmap("ic_call_missed_holo_dark"));
+        mCallTypeIcons.put(Calls.OUTGOING_TYPE, getBitmap("ic_call_outgoing_holo_dark"));
     }
 
     //
diff --git a/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java b/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
index a8714b4..b311454 100644
--- a/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
+++ b/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
@@ -19,9 +19,11 @@
 import com.android.contacts.PhoneCallDetails;
 import com.android.contacts.PhoneCallDetailsHelper;
 import com.android.contacts.PhoneCallDetailsViews;
+import com.android.contacts.R;
 import com.android.internal.telephony.CallerInfo;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -43,6 +45,8 @@
     private static final String TEST_FORMATTED_NUMBER = "1-412-255-5555";
     /** A test date value for phone calls. */
     private static final long TEST_DATE = 1300000000;
+    /** A test duration value for phone calls. */
+    private static final long TEST_DURATION = 62300;
     /** A test voicemail number. */
     private static final String TEST_VOICEMAIL_NUMBER = "123";
     /** A drawable to be used for incoming calls. */
@@ -68,11 +72,18 @@
     protected void setUp() throws Exception {
         super.setUp();
         Context context = getContext();
+        Resources resources = context.getResources();
+        CallTypeHelper callTypeHelper = new CallTypeHelper(resources,
+                resources.getDrawable(R.drawable.ic_call_incoming_holo_dark),
+                resources.getDrawable(R.drawable.ic_call_outgoing_holo_dark),
+                resources.getDrawable(R.drawable.ic_call_missed_holo_dark),
+                resources.getDrawable(R.drawable.ic_call_voicemail_holo_dark));
+        PhoneNumberHelper phoneNumberHelper =
+                new PhoneNumberHelper(resources, TEST_VOICEMAIL_NUMBER);
         PhoneCallDetailsHelper phoneCallDetailsHelper = new PhoneCallDetailsHelper(context,
-                context.getResources(), TEST_VOICEMAIL_NUMBER, TEST_INCOMING_DRAWABLE,
-                TEST_OUTGOING_DRAWABLE, TEST_MISSED_DRAWABLE, TEST_VOICEMAIL_DRAWABLE);
-        mHelper = new CallLogListItemHelper(phoneCallDetailsHelper, TEST_CALL_DRAWABLE,
-                TEST_PLAY_DRAWABLE);
+                resources, callTypeHelper, phoneNumberHelper);
+        mHelper = new CallLogListItemHelper(phoneCallDetailsHelper, phoneNumberHelper,
+                TEST_CALL_DRAWABLE, TEST_PLAY_DRAWABLE);
         mViews = CallLogListItemViews.createForTest(new QuickContactBadge(context),
                 new ImageView(context), PhoneCallDetailsViews.createForTest(new TextView(context),
                         new LinearLayout(context), new TextView(context), new TextView(context),
@@ -123,13 +134,15 @@
     private void setPhoneCallDetailsWithNumber(String number, String formattedNumber) {
         mHelper.setPhoneCallDetails(mViews,
                 new PhoneCallDetails(number, formattedNumber, new int[]{ Calls.INCOMING_TYPE },
-                        TEST_DATE),
+                        TEST_DATE, TEST_DURATION),
                 true);
     }
 
     /** Sets the details of a phone call using the specified call type. */
     private void setPhoneCallDetailsWithTypes(int... types) {
         mHelper.setPhoneCallDetails(mViews,
-                new PhoneCallDetails(TEST_NUMBER, TEST_FORMATTED_NUMBER, types, TEST_DATE), true);
+                new PhoneCallDetails(
+                        TEST_NUMBER, TEST_FORMATTED_NUMBER, types, TEST_DATE, TEST_DURATION),
+                true);
     }
 }
diff --git a/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java b/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
index 71012de..8c37a02 100644
--- a/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
+++ b/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
@@ -29,6 +29,7 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
+import android.provider.CallLog.Calls;
 import android.provider.Contacts.ContactMethods;
 import android.provider.Contacts.People;
 import android.provider.Contacts.Phones;
@@ -55,6 +56,7 @@
 public class AllIntentsActivity extends ListActivity
         implements SelectAccountDialogFragment.Listener {
 
+    /** The name of the package of the contacts application. */
     private static final String ANDROID_CONTACTS_PACKAGE = "com.android.contacts";
 
     private static final String CONTACT_LIST_ACTIVITY_CLASS_NAME =
@@ -116,7 +118,10 @@
         CALL_BUTTON,
         DIAL_tel,
         VIEW_tel,
-        VIEW_calllog;
+        VIEW_calllog,
+        VIEW_calllog_entry,
+        LEGACY_CALL_DETAILS_ACTIVITY,
+        LEGACY_CALL_LOG_ACTIVITY;
 
         public static ContactsIntent get(int ordinal) {
             return values()[ordinal];
@@ -208,15 +213,13 @@
             }
             case ACTION_CREATE_SHORTCUT_DIAL: {
                 Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
-                intent.setComponent(
-                        new ComponentName(ANDROID_CONTACTS_PACKAGE, "alias.DialShortcut"));
+                bindIntentToClass(intent, "alias.DialShortcut");
                 startActivityForResult(intent, 0);
                 break;
             }
             case ACTION_CREATE_SHORTCUT_MESSAGE: {
                 Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
-                intent.setComponent(
-                        new ComponentName(ANDROID_CONTACTS_PACKAGE, "alias.MessageShortcut"));
+                bindIntentToClass(intent, "alias.MessageShortcut");
                 startActivityForResult(intent, 0);
                 break;
             }
@@ -483,12 +486,57 @@
                 startActivity(intent);
                 break;
             }
+            case VIEW_calllog_entry: {
+                Uri uri = getCallLogUri();
+                if (uri == null) {
+                    Toast.makeText(this, "Call log is empty", Toast.LENGTH_LONG).show();
+                    break;
+                }
+                final Intent intent = new Intent(Intent.ACTION_VIEW);
+                intent.setData(uri);
+                startActivity(intent);
+                break;
+            }
+            case LEGACY_CALL_DETAILS_ACTIVITY: {
+                Uri uri = getCallLogUri();
+                if (uri == null) {
+                    Toast.makeText(this, "Call log is empty", Toast.LENGTH_LONG).show();
+                    break;
+                }
+                final Intent intent = new Intent("android.intent.action.VIEW");
+                intent.setData(uri);
+                bindIntentToClass(intent, "CallDetailActivity");
+                startActivity(intent);
+                break;
+            }
+            case LEGACY_CALL_LOG_ACTIVITY: {
+                startActivity(bindIntentToClass(new Intent(), "activities.CallLogActivity"));
+                break;
+            }
+
             default: {
                 Toast.makeText(this, "Sorry, we forgot to write this...", Toast.LENGTH_LONG).show();
             }
         }
     }
 
+    /** Returns the URI of one of the items in the call log, or null if the call log is empty. */
+    private Uri getCallLogUri() {
+        Cursor cursor = getContentResolver().query(
+                Calls.CONTENT_URI, new String[]{ Calls._ID }, null, null,
+                Calls.DEFAULT_SORT_ORDER);
+        if (!cursor.moveToNext()) {
+            return null;
+        }
+        return ContentUris.withAppendedId(Calls.CONTENT_URI, cursor.getLong(0));
+    }
+
+    /** Creates an intent that is bound to a specific activity by name. */
+    private Intent bindIntentToClass(Intent intent, String activityClassName) {
+        intent.setComponent(new ComponentName(ANDROID_CONTACTS_PACKAGE, activityClassName));
+        return intent;
+    }
+
     private Intent buildFilterIntent(int actionCode, boolean legacy) {
         Intent intent = new Intent(UI.FILTER_CONTACTS_ACTION);
         intent.putExtra(UI.FILTER_TEXT_EXTRA_KEY, "A");
@@ -499,8 +547,7 @@
     }
 
     private void startContactListActivity(Intent intent) {
-        intent.setComponent(
-                new ComponentName(ANDROID_CONTACTS_PACKAGE, CONTACT_LIST_ACTIVITY_CLASS_NAME));
+        bindIntentToClass(intent, CONTACT_LIST_ACTIVITY_CLASS_NAME);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         startActivity(intent);
     }