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);
}