Merge "Fix contact editor account header"
diff --git a/res/color/list_primary_text_color.xml b/res/color/list_primary_text_color.xml
new file mode 100644
index 0000000..7c185fc
--- /dev/null
+++ b/res/color/list_primary_text_color.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_activated="true" android:color="@color/primary_text_color_activated"/>
+ <item android:color="@color/primary_text_color" /> <!-- not selected -->
+
+</selector>
diff --git a/res/color/list_secondary_text_color.xml b/res/color/list_secondary_text_color.xml
new file mode 100644
index 0000000..edf8678
--- /dev/null
+++ b/res/color/list_secondary_text_color.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_activated="true" android:color="@color/secondary_text_color_activated" />
+ <item android:color="@color/secondary_text_color" /> <!-- not selected -->
+
+</selector>
diff --git a/res/drawable-hdpi/ab_solid_custom_blue_inverse_holo.9.png b/res/drawable-hdpi/ab_solid_custom_blue_inverse_holo.9.png
index 80fb400..956d61b 100644
--- a/res/drawable-hdpi/ab_solid_custom_blue_inverse_holo.9.png
+++ b/res/drawable-hdpi/ab_solid_custom_blue_inverse_holo.9.png
Binary files differ
diff --git a/res/drawable-hdpi/account_spinner_icon.png b/res/drawable-hdpi/account_spinner_icon.png
index 3e82e51..9566386 100644
--- a/res/drawable-hdpi/account_spinner_icon.png
+++ b/res/drawable-hdpi/account_spinner_icon.png
Binary files differ
diff --git a/res/drawable-hdpi/action_bar_item_pressed_holo_light.9.png b/res/drawable-hdpi/action_bar_item_pressed_holo_light.9.png
new file mode 100644
index 0000000..cf5ff8e
--- /dev/null
+++ b/res/drawable-hdpi/action_bar_item_pressed_holo_light.9.png
Binary files differ
diff --git a/res/drawable-hdpi/list_activated_holo.9.png b/res/drawable-hdpi/list_activated_holo.9.png
index 046b24a..4ea7afa 100644
--- a/res/drawable-hdpi/list_activated_holo.9.png
+++ b/res/drawable-hdpi/list_activated_holo.9.png
Binary files differ
diff --git a/res/drawable-hdpi/list_focused_holo.9.png b/res/drawable-hdpi/list_focused_holo.9.png
index e962ce8..516f5c7 100644
--- a/res/drawable-hdpi/list_focused_holo.9.png
+++ b/res/drawable-hdpi/list_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-hdpi/list_pressed_holo_light.9.png b/res/drawable-hdpi/list_pressed_holo_light.9.png
index cf5ff8e..5654cd6 100644
--- a/res/drawable-hdpi/list_pressed_holo_light.9.png
+++ b/res/drawable-hdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/res/drawable-hdpi/list_section_divider_holo_custom.9.png b/res/drawable-hdpi/list_section_divider_holo_custom.9.png
index 6c0d251..1e3e778 100644
--- a/res/drawable-hdpi/list_section_divider_holo_custom.9.png
+++ b/res/drawable-hdpi/list_section_divider_holo_custom.9.png
Binary files differ
diff --git a/res/drawable-mdpi/ab_solid_custom_blue_inverse_holo.9.png b/res/drawable-mdpi/ab_solid_custom_blue_inverse_holo.9.png
index f3c0a90..3e9f167 100644
--- a/res/drawable-mdpi/ab_solid_custom_blue_inverse_holo.9.png
+++ b/res/drawable-mdpi/ab_solid_custom_blue_inverse_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/account_spinner_icon.png b/res/drawable-mdpi/account_spinner_icon.png
index d9aaf02..e159d59 100644
--- a/res/drawable-mdpi/account_spinner_icon.png
+++ b/res/drawable-mdpi/account_spinner_icon.png
Binary files differ
diff --git a/res/drawable-mdpi/action_bar_item_pressed_holo_light.9.png b/res/drawable-mdpi/action_bar_item_pressed_holo_light.9.png
new file mode 100644
index 0000000..3a9686d
--- /dev/null
+++ b/res/drawable-mdpi/action_bar_item_pressed_holo_light.9.png
Binary files differ
diff --git a/res/drawable-mdpi/list_activated_holo.9.png b/res/drawable-mdpi/list_activated_holo.9.png
index 1ff3373..3bf8e03 100644
--- a/res/drawable-mdpi/list_activated_holo.9.png
+++ b/res/drawable-mdpi/list_activated_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/list_focused_holo.9.png b/res/drawable-mdpi/list_focused_holo.9.png
index 6e041f3..7c0599e 100644
--- a/res/drawable-mdpi/list_focused_holo.9.png
+++ b/res/drawable-mdpi/list_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/list_pressed_holo_light.9.png b/res/drawable-mdpi/list_pressed_holo_light.9.png
index 3a9686d..6e77525 100644
--- a/res/drawable-mdpi/list_pressed_holo_light.9.png
+++ b/res/drawable-mdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/res/drawable-mdpi/list_section_divider_holo_custom.9.png b/res/drawable-mdpi/list_section_divider_holo_custom.9.png
index cfc57ee..1d8fd09 100644
--- a/res/drawable-mdpi/list_section_divider_holo_custom.9.png
+++ b/res/drawable-mdpi/list_section_divider_holo_custom.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/ab_solid_custom_blue_inverse_holo.9.png b/res/drawable-xhdpi/ab_solid_custom_blue_inverse_holo.9.png
index 3c97b20..31fea59 100644
--- a/res/drawable-xhdpi/ab_solid_custom_blue_inverse_holo.9.png
+++ b/res/drawable-xhdpi/ab_solid_custom_blue_inverse_holo.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/account_spinner_icon.png b/res/drawable-xhdpi/account_spinner_icon.png
index 8b888cb..d3d3cac 100644
--- a/res/drawable-xhdpi/account_spinner_icon.png
+++ b/res/drawable-xhdpi/account_spinner_icon.png
Binary files differ
diff --git a/res/drawable-xhdpi/action_bar_item_pressed_holo_light.9.png b/res/drawable-xhdpi/action_bar_item_pressed_holo_light.9.png
new file mode 100644
index 0000000..8ff9dca
--- /dev/null
+++ b/res/drawable-xhdpi/action_bar_item_pressed_holo_light.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/list_activated_holo.9.png b/res/drawable-xhdpi/list_activated_holo.9.png
index 2eb7c7e..eda10e6 100644
--- a/res/drawable-xhdpi/list_activated_holo.9.png
+++ b/res/drawable-xhdpi/list_activated_holo.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/list_focused_holo.9.png b/res/drawable-xhdpi/list_focused_holo.9.png
index 9c90c2b..690cb1e 100644
--- a/res/drawable-xhdpi/list_focused_holo.9.png
+++ b/res/drawable-xhdpi/list_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/list_pressed_holo_light.9.png b/res/drawable-xhdpi/list_pressed_holo_light.9.png
index 8ff9dca..e4b3393 100644
--- a/res/drawable-xhdpi/list_pressed_holo_light.9.png
+++ b/res/drawable-xhdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/list_section_divider_holo_custom.9.png b/res/drawable-xhdpi/list_section_divider_holo_custom.9.png
index 32e79e1..0bd8a0f 100644
--- a/res/drawable-xhdpi/list_section_divider_holo_custom.9.png
+++ b/res/drawable-xhdpi/list_section_divider_holo_custom.9.png
Binary files differ
diff --git a/res/drawable/action_bar_item_background.xml b/res/drawable/action_bar_item_background.xml
index 1fd4614..8dd8d9b 100644
--- a/res/drawable/action_bar_item_background.xml
+++ b/res/drawable/action_bar_item_background.xml
@@ -16,6 +16,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
- <item android:state_pressed="true" android:drawable="@drawable/list_pressed_holo_light"/>
+ <item android:state_pressed="true" android:drawable="@drawable/action_bar_item_pressed_holo_light"/>
<item android:drawable="@android:color/transparent" />
-</selector>
\ No newline at end of file
+</selector>
diff --git a/res/drawable/group_list_item_background.xml b/res/drawable/group_list_item_background.xml
index 0e2e604..345117f 100644
--- a/res/drawable/group_list_item_background.xml
+++ b/res/drawable/group_list_item_background.xml
@@ -17,6 +17,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
<item android:state_activated="true" android:drawable="@drawable/list_activated_holo" />
- <item android:state_pressed="true" android:drawable="@drawable/list_pressed_holo" />
+ <item android:state_pressed="true" android:drawable="@drawable/list_pressed_holo_light" />
<item android:state_focused="true" android:drawable="@drawable/list_focused_holo" />
-</selector>
\ No newline at end of file
+</selector>
diff --git a/res/drawable/list_item_activated_background.xml b/res/drawable/list_item_activated_background.xml
index 6ea21d3..a58577e 100644
--- a/res/drawable/list_item_activated_background.xml
+++ b/res/drawable/list_item_activated_background.xml
@@ -14,8 +14,7 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="true" android:drawable="@drawable/list_activated_holo" />
<item android:drawable="@drawable/list_background_holo" />
-</selector>
\ No newline at end of file
+</selector>
diff --git a/res/layout-sw580dp/contact_detail_container.xml b/res/layout-sw580dp/contact_detail_container.xml
index 58a6eb3..cdb789f 100644
--- a/res/layout-sw580dp/contact_detail_container.xml
+++ b/res/layout-sw580dp/contact_detail_container.xml
@@ -17,8 +17,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical"
- android:background="@color/background_primary">
+ android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="@+id/pager"
diff --git a/res/layout-sw580dp/group_detail_fragment.xml b/res/layout-sw580dp/group_detail_fragment.xml
index 90ca03a..438a987 100644
--- a/res/layout-sw580dp/group_detail_fragment.xml
+++ b/res/layout-sw580dp/group_detail_fragment.xml
@@ -22,8 +22,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/group_detail_border_padding"
- android:paddingRight="@dimen/group_detail_border_padding"
- android:background="@drawable/panel_content">
+ android:paddingRight="@dimen/group_detail_border_padding">
<TextView
android:id="@+id/group_title"
diff --git a/res/layout-sw580dp/people_activity.xml b/res/layout-sw580dp/people_activity.xml
index e15c079..fecb848 100644
--- a/res/layout-sw580dp/people_activity.xml
+++ b/res/layout-sw580dp/people_activity.xml
@@ -58,6 +58,7 @@
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
+ android:background="@color/background_primary"
ex:clipMarginLeft="0dip"
ex:clipMarginTop="3dip"
ex:clipMarginRight="3dip"
@@ -72,7 +73,10 @@
android:id="@+id/contact_detail_container"
layout="@layout/contact_detail_container"
android:layout_width="match_parent"
- android:layout_height="match_parent"/>
+ android:layout_height="match_parent"
+ android:layout_marginTop="16dip"
+ android:layout_marginLeft="16dip"
+ android:layout_marginRight="16dip"/>
<!-- This invisible worker fragment loads the contact's details -->
<fragment
diff --git a/res/layout/call_detail.xml b/res/layout/call_detail.xml
index df1ec62..c69f89f 100644
--- a/res/layout/call_detail.xml
+++ b/res/layout/call_detail.xml
@@ -196,4 +196,18 @@
</LinearLayout>
</FrameLayout>
</RelativeLayout>
+
+ <!--
+ Used to hide the UI when playing a voicemail and the proximity sensor
+ is detecting something near the screen.
+ -->
+ <View
+ android:id="@+id/blank"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:background="#000000"
+ android:visibility="gone"
+ />
</RelativeLayout>
diff --git a/res/layout/group_browse_list_item.xml b/res/layout/group_browse_list_item.xml
index cc388f7..b213754 100644
--- a/res/layout/group_browse_list_item.xml
+++ b/res/layout/group_browse_list_item.xml
@@ -71,6 +71,7 @@
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/list_primary_text_color"
android:ellipsize="end"
android:singleLine="true" />
@@ -79,7 +80,7 @@
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorTertiary"
+ android:textColor="@color/list_secondary_text_color"
android:ellipsize="end"
android:singleLine="true" />
diff --git a/res/layout/item_read_only_field.xml b/res/layout/item_read_only_field.xml
index 03778cc..5f8367f 100644
--- a/res/layout/item_read_only_field.xml
+++ b/res/layout/item_read_only_field.xml
@@ -14,7 +14,8 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
@@ -23,13 +24,29 @@
android:id="@+id/kind_title_layout"
layout="@layout/edit_kind_title" />
- <TextView android:id="@+id/data"
- android:layout_width="wrap_content"
- android:layout_height="0px"
- android:layout_weight="1"
- android:layout_marginLeft="16dip"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorSecondary"
- android:singleLine="true"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/editor_min_line_item_height"
+ android:orientation="horizontal">
+ <TextView
+ android:id="@+id/data"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginLeft="16dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorPrimary"
+ android:singleLine="true"/>
+ <TextView
+ android:id="@+id/type"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginLeft="8dip"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"
+ android:singleLine="true"/>
+ </LinearLayout>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/res/layout/stream_item_container.xml b/res/layout/stream_item_container.xml
index 308c5f5..de4f87d 100644
--- a/res/layout/stream_item_container.xml
+++ b/res/layout/stream_item_container.xml
@@ -21,7 +21,7 @@
android:paddingLeft="@dimen/detail_update_section_side_padding"
android:paddingRight="@dimen/detail_update_section_side_padding">
- <TableLayout
+ <LinearLayout
android:id="@+id/stream_item_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -31,6 +31,7 @@
android:paddingBottom="@dimen/detail_update_section_item_vertical_padding"
android:background="?android:attr/selectableItemBackground"
android:layout_gravity="center_vertical"
+ android:orientation="vertical"
/>
<View
diff --git a/res/layout/stream_item_row_image_and_text.xml b/res/layout/stream_item_row_image_and_text.xml
index 882a23b..c5699f4 100644
--- a/res/layout/stream_item_row_image_and_text.xml
+++ b/res/layout/stream_item_row_image_and_text.xml
@@ -14,68 +14,41 @@
limitations under the License.
-->
-<TableRow
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts">
+ xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
- <view
- class="com.android.contacts.widget.ProportionalLayout"
- android:layout_width="0dip"
+ <LinearLayout
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginRight="@dimen/detail_update_section_between_items_horizontal_padding"
- android:layout_weight="1"
- ex:ratio="1"
- ex:direction="widthToHeight">
- <include
- android:id="@+id/stream_item_first_image"
- layout="@layout/stream_item_photo"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
- </view>
+ android:layout_marginBottom="8dip"
+ android:orientation="horizontal"
+ android:weightSum="2">
- <view
- class="com.android.contacts.widget.ProportionalLayout"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- ex:ratio="1"
- ex:direction="widthToHeight">
- <LinearLayout
- android:id="@+id/stream_item_second_text"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ <view
+ class="com.android.contacts.widget.ProportionalLayout"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginRight="@dimen/detail_update_section_between_items_horizontal_padding"
+ ex:ratio="1"
+ ex:direction="widthToHeight">
- <TextView android:id="@+id/stream_item_html"
+ <include
+ android:id="@+id/stream_item_first_image"
+ layout="@layout/stream_item_photo"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textSize="16sp"
- android:textColor="?android:attr/textColorPrimary" />
+ android:layout_height="match_parent"/>
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <TextView android:id="@+id/stream_item_attribution"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorSecondary"
- android:maxLines="1"
- android:ellipsize="end"
- android:layout_weight="1" />
+ </view>
- <TextView android:id="@+id/stream_item_comments"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/detail_update_section_attribution_comments_padding"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorSecondary"
- android:visibility="gone"
- android:maxLines="1" />
- </LinearLayout>
+ </LinearLayout>
- </LinearLayout>
- </view>
+ <include
+ android:id="@+id/stream_item_second_text"
+ layout="@layout/stream_item_row_text_only"/>
-</TableRow>
+</LinearLayout>
diff --git a/res/layout/stream_item_row_two_images.xml b/res/layout/stream_item_row_two_images.xml
index f10b7d8..3a524bf 100644
--- a/res/layout/stream_item_row_two_images.xml
+++ b/res/layout/stream_item_row_two_images.xml
@@ -14,9 +14,11 @@
limitations under the License.
-->
-<TableRow
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts">
+ xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
<view
class="com.android.contacts.widget.ProportionalLayout"
@@ -47,4 +49,4 @@
android:layout_height="match_parent"/>
</view>
-</TableRow>
+</LinearLayout>
diff --git a/res/menu-sw580dp-w720dp/actions.xml b/res/menu-sw580dp-w720dp/actions.xml
index 3aca102..2d21676 100644
--- a/res/menu-sw580dp-w720dp/actions.xml
+++ b/res/menu-sw580dp-w720dp/actions.xml
@@ -39,21 +39,20 @@
android:title="@string/menu_contacts_filter" />
<item
- android:id="@+id/menu_settings"
- android:icon="@drawable/ic_menu_settings_holo_light"
- android:orderInCategory="2"
- android:title="@string/menu_settings" />
-
- <item
android:id="@+id/menu_import_export"
android:icon="@drawable/ic_menu_import_export_holo_light"
- android:orderInCategory="3"
+ android:orderInCategory="2"
android:title="@string/menu_import_export" />
<item
android:id="@+id/menu_accounts"
android:icon="@drawable/ic_menu_accounts_holo_light"
- android:orderInCategory="4"
+ android:orderInCategory="3"
android:title="@string/menu_accounts" />
+ <item
+ android:id="@+id/menu_settings"
+ android:icon="@drawable/ic_menu_settings_holo_light"
+ android:orderInCategory="4"
+ android:title="@string/menu_settings" />
</menu>
diff --git a/res/menu-sw580dp/actions.xml b/res/menu-sw580dp/actions.xml
index c2fd3e6..08fea42 100644
--- a/res/menu-sw580dp/actions.xml
+++ b/res/menu-sw580dp/actions.xml
@@ -42,21 +42,20 @@
android:title="@string/menu_contacts_filter" />
<item
- android:id="@+id/menu_settings"
- android:icon="@drawable/ic_menu_settings_holo_light"
- android:orderInCategory="2"
- android:title="@string/menu_settings" />
-
- <item
android:id="@+id/menu_import_export"
android:icon="@drawable/ic_menu_import_export_holo_light"
- android:orderInCategory="3"
+ android:orderInCategory="2"
android:title="@string/menu_import_export" />
<item
android:id="@+id/menu_accounts"
android:icon="@drawable/ic_menu_accounts_holo_light"
- android:orderInCategory="4"
+ android:orderInCategory="3"
android:title="@string/menu_accounts" />
+ <item
+ android:id="@+id/menu_settings"
+ android:icon="@drawable/ic_menu_settings_holo_light"
+ android:orderInCategory="4"
+ android:title="@string/menu_settings" />
</menu>
diff --git a/res/menu/actions.xml b/res/menu/actions.xml
index 2af9e92..852bfa9 100644
--- a/res/menu/actions.xml
+++ b/res/menu/actions.xml
@@ -38,11 +38,6 @@
android:title="@string/menu_contacts_filter" />
<item
- android:id="@+id/menu_settings"
- android:icon="@drawable/ic_menu_settings_holo_light"
- android:title="@string/menu_settings" />
-
- <item
android:id="@+id/menu_import_export"
android:icon="@drawable/ic_menu_import_export_holo_light"
android:title="@string/menu_import_export" />
@@ -52,4 +47,8 @@
android:icon="@drawable/ic_menu_accounts_holo_light"
android:title="@string/menu_accounts" />
+ <item
+ android:id="@+id/menu_settings"
+ android:icon="@drawable/ic_menu_settings_holo_light"
+ android:title="@string/menu_settings" />
</menu>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 0b8f1b7..5e8bd70 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -83,10 +83,16 @@
<!-- Primary text color in the People app -->
<color name="primary_text_color">#333333</color>
+ <!-- Activated primary text color in the People app -->
+ <color name="primary_text_color_activated">#FFFFFF</color>
+
<!-- Secondary text color in the People app -->
<color name="secondary_text_color">#777777</color>
<color name="dialtacts_secondary_text_color">#888888</color>
+ <!-- Activated secondary text color in the People app -->
+ <color name="secondary_text_color_activated">#FFFFFF</color>
+
<!-- Colors in the contact browser list -->
<color name="contact_count_text_color">#AAAAAA</color>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 102ddbd..43c4107 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1490,7 +1490,7 @@
<string name="activity_title_contacts_filter">Contacts to display</string>
<!-- Menu item for the settings activity [CHAR LIMIT=64] -->
- <string name="menu_settings">Display options</string>
+ <string name="menu_settings" msgid="377929915873428211">Settings</string>
<!-- The preference section title for contact display options [CHAR LIMIT=128] -->
<string name="preference_displayOptions">Display options</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index dc209c5..0a5352a 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -181,6 +181,8 @@
</style>
<style name="ContactPickerTheme" parent="@style/PeopleTheme">
+ <item name="android:windowActionBar">false</item>
+ <item name="android:windowNoTitle">true</item>
</style>
<style name="ContactPickerLayout" parent="ContactPickerTheme">
<item name="android:layout_width">match_parent</item>
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index 6ab4b68..0fadbfb 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -69,9 +69,14 @@
* 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 Activity {
+public class CallDetailActivity extends Activity implements ProximitySensorAware {
private static final String TAG = "CallDetail";
+ /** The time to wait before enabling the blank the screen due to the proximity sensor. */
+ private static final long PROXIMITY_BLANK_DELAY_MILLIS = 100;
+ /** The time to wait before disabling the blank the screen due to the proximity sensor. */
+ private static final long PROXIMITY_UNBLANK_DELAY_MILLIS = 500;
+
/** The enumeration of {@link AsyncTask} objects used in this class. */
public enum Tasks {
MARK_VOICEMAIL_READ,
@@ -115,6 +120,60 @@
/** Whether we should show "edit number before call" in the options menu. */
private boolean mHasEditNumberBeforeCall;
+ private ProximitySensorManager mProximitySensorManager;
+ private final ProximitySensorListener mProximitySensorListener = new ProximitySensorListener();
+
+ /** Listener to changes in the proximity sensor state. */
+ private class ProximitySensorListener implements ProximitySensorManager.Listener {
+ /** Used to show a blank view and hide the action bar. */
+ private final Runnable mBlankRunnable = new Runnable() {
+ @Override
+ public void run() {
+ View blankView = findViewById(R.id.blank);
+ blankView.setVisibility(View.VISIBLE);
+ getActionBar().hide();
+ }
+ };
+ /** Used to remove the blank view and show the action bar. */
+ private final Runnable mUnblankRunnable = new Runnable() {
+ @Override
+ public void run() {
+ View blankView = findViewById(R.id.blank);
+ blankView.setVisibility(View.GONE);
+ getActionBar().show();
+ }
+ };
+
+ @Override
+ public synchronized void onNear() {
+ clearPendingRequests();
+ postDelayed(mBlankRunnable, PROXIMITY_BLANK_DELAY_MILLIS);
+ }
+
+ @Override
+ public synchronized void onFar() {
+ clearPendingRequests();
+ postDelayed(mUnblankRunnable, PROXIMITY_UNBLANK_DELAY_MILLIS);
+ }
+
+ /** Removed any delayed requests that may be pending. */
+ public synchronized void clearPendingRequests() {
+ View blankView = findViewById(R.id.blank);
+ blankView.removeCallbacks(mBlankRunnable);
+ blankView.removeCallbacks(mUnblankRunnable);
+ }
+
+ /** Post a {@link Runnable} with a delay on the main thread. */
+ private synchronized void postDelayed(Runnable runnable, long delayMillis) {
+ // Post these instead of executing immediately so that:
+ // - They are guaranteed to be executed on the main thread.
+ // - If the sensor values changes rapidly for some time, the UI will not be
+ // updated immediately.
+ View blankView = findViewById(R.id.blank);
+ blankView.postDelayed(runnable, delayMillis);
+ }
+ }
+
static final String[] CALL_LOG_PROJECTION = new String[] {
CallLog.Calls.DATE,
CallLog.Calls.DURATION,
@@ -189,6 +248,7 @@
mContactBackgroundView = (ImageView) findViewById(R.id.contact_background);
mDefaultCountryIso = ContactsUtils.getCurrentCountryIso(this);
mContactPhotoManager = ContactPhotoManager.getInstance(this);
+ mProximitySensorManager = new ProximitySensorManager(this, mProximitySensorListener);
configureActionBar();
optionallyHandleVoicemail();
}
@@ -770,4 +830,22 @@
startActivity(intent);
finish();
}
+
+ @Override
+ protected void onPause() {
+ // Immediately stop the proximity sensor.
+ disableProximitySensor(false);
+ mProximitySensorListener.clearPendingRequests();
+ super.onPause();
+ }
+
+ @Override
+ public void enableProximitySensor() {
+ mProximitySensorManager.enable();
+ }
+
+ @Override
+ public void disableProximitySensor(boolean waitForFarState) {
+ mProximitySensorManager.disable(waitForFarState);
+ }
}
diff --git a/src/com/android/contacts/ProximitySensorAware.java b/src/com/android/contacts/ProximitySensorAware.java
new file mode 100644
index 0000000..0fb233d
--- /dev/null
+++ b/src/com/android/contacts/ProximitySensorAware.java
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+/**
+ * An object that is aware of the state of the proximity sensor.
+ */
+public interface ProximitySensorAware {
+ /** Start tracking the state of the proximity sensor. */
+ public void enableProximitySensor();
+
+ /**
+ * Stop tracking the state of the proximity sensor.
+ *
+ * @param waitForFarState if true and the sensor is currently in the near state, it will wait
+ * until it is again in the far state before stopping to track its state.
+ */
+ public void disableProximitySensor(boolean waitForFarState);
+}
diff --git a/src/com/android/contacts/ProximitySensorManager.java b/src/com/android/contacts/ProximitySensorManager.java
new file mode 100644
index 0000000..69601bf
--- /dev/null
+++ b/src/com/android/contacts/ProximitySensorManager.java
@@ -0,0 +1,237 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+
+import javax.annotation.concurrent.GuardedBy;
+
+/**
+ * Manages the proximity sensor and notifies a listener when enabled.
+ */
+public class ProximitySensorManager {
+ /**
+ * Listener of the state of the proximity sensor.
+ * <p>
+ * This interface abstracts two possible states for the proximity sensor, near and far.
+ * <p>
+ * The actual meaning of these states depends on the actual sensor.
+ */
+ public interface Listener {
+ /** Called when the proximity sensor transitions from the far to the near state. */
+ public void onNear();
+ /** Called when the proximity sensor transitions from the near to the far state. */
+ public void onFar();
+ }
+
+ public static enum State {
+ NEAR, FAR
+ }
+
+ private final ProximitySensorEventListener mProximitySensorListener;
+
+ /**
+ * The current state of the manager, i.e., whether it is currently tracking the state of the
+ * sensor.
+ */
+ private boolean mManagerEnabled;
+
+ /**
+ * The listener to the state of the sensor.
+ * <p>
+ * Contains most of the logic concerning tracking of the sensor.
+ * <p>
+ * After creating an instance of this object, one should call {@link #register()} and
+ * {@link #unregister()} to enable and disable the notifications.
+ * <p>
+ * Instead of calling unregister, one can call {@link #unregisterWhenFar()} to unregister the
+ * listener the next time the sensor reaches the {@link State#FAR} state if currently in the
+ * {@link State#NEAR} state.
+ */
+ private static class ProximitySensorEventListener implements SensorEventListener {
+ private static final float FAR_THRESHOLD = 5.0f;
+
+ private final SensorManager mSensorManager;
+ private final Sensor mProximitySensor;
+ private final float mMaxValue;
+ private final Listener mListener;
+
+ /**
+ * The last state of the sensor.
+ * <p>
+ * Before registering and after unregistering we are always in the {@link State#FAR} state.
+ */
+ @GuardedBy("this") private State mLastState;
+ /**
+ * If this flag is set to true, we are waiting to reach the {@link State#FAR} state and
+ * should notify the listener and unregister when that happens.
+ */
+ @GuardedBy("this") private boolean mWaitingForFarState;
+
+ public ProximitySensorEventListener(SensorManager sensorManager, Sensor proximitySensor,
+ Listener listener) {
+ mSensorManager = sensorManager;
+ mProximitySensor = proximitySensor;
+ mMaxValue = proximitySensor.getMaximumRange();
+ mListener = listener;
+ // Initialize at far state.
+ mLastState = State.FAR;
+ mWaitingForFarState = false;
+ }
+
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ // Make sure we have a valid value.
+ if (event.values == null) return;
+ if (event.values.length == 0) return;
+ float value = event.values[0];
+ // Convert the sensor into a NEAR/FAR state.
+ State state = getStateFromValue(value);
+ synchronized (this) {
+ // No change in state, do nothing.
+ if (state == mLastState) return;
+ // Keep track of the current state.
+ mLastState = state;
+ // If we are waiting to reach the far state and we are now in it, unregister.
+ if (mWaitingForFarState && mLastState == State.FAR) {
+ unregisterWithoutNotification();
+ }
+ }
+ // Notify the listener of the state change.
+ switch (state) {
+ case NEAR:
+ mListener.onNear();
+ break;
+
+ case FAR:
+ mListener.onFar();
+ break;
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // Nothing to do here.
+ }
+
+ /** Returns the state of the sensor given its current value. */
+ private State getStateFromValue(float value) {
+ // Determine if the current value corresponds to the NEAR or FAR state.
+ // Take case of the case where the proximity sensor is binary: if the current value is
+ // equal to the maximum, we are always in the FAR state.
+ return (value > FAR_THRESHOLD || value == mMaxValue) ? State.FAR : State.NEAR;
+ }
+
+ /**
+ * Unregister the next time the sensor reaches the {@link State#FAR} state.
+ */
+ public synchronized void unregisterWhenFar() {
+ if (mLastState == State.FAR) {
+ // We are already in the far state, just unregister now.
+ unregisterWithoutNotification();
+ } else {
+ mWaitingForFarState = true;
+ }
+ }
+
+ /** Register the listener and call the listener as necessary. */
+ public synchronized void register() {
+ // It is okay to register multiple times.
+ mSensorManager.registerListener(this, mProximitySensor, SensorManager.SENSOR_DELAY_UI);
+ // We should no longer be waiting for the far state if we are registering again.
+ mWaitingForFarState = false;
+ }
+
+ public void unregister() {
+ State lastState;
+ synchronized (this) {
+ unregisterWithoutNotification();
+ lastState = mLastState;
+ // Always go back to the FAR state. That way, when we register again we will get a
+ // transition when the sensor gets into the NEAR state.
+ mLastState = State.FAR;
+ }
+ // Notify the listener if we changed the state to FAR while unregistering.
+ if (lastState != State.FAR) {
+ mListener.onFar();
+ }
+ }
+
+ @GuardedBy("this")
+ private void unregisterWithoutNotification() {
+ mSensorManager.unregisterListener(this);
+ mWaitingForFarState = false;
+ }
+ }
+
+ public ProximitySensorManager(Context context, Listener listener) {
+ SensorManager sensorManager =
+ (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+ Sensor proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+ if (proximitySensor == null) {
+ // If there is no sensor, we should not do anything.
+ mProximitySensorListener = null;
+ } else {
+ mProximitySensorListener =
+ new ProximitySensorEventListener(sensorManager, proximitySensor, listener);
+ }
+ }
+
+ /**
+ * Enables the proximity manager.
+ * <p>
+ * The listener will start getting notifications of events.
+ * <p>
+ * This method is idempotent.
+ */
+ public void enable() {
+ if (mProximitySensorListener != null && !mManagerEnabled) {
+ mProximitySensorListener.register();
+ mManagerEnabled = true;
+ }
+ }
+
+ /**
+ * Disables the proximity manager.
+ * <p>
+ * The listener will stop receiving notifications of events, possibly after receiving a last
+ * {@link Listener#onFar()} callback.
+ * <p>
+ * If {@code waitForFarState} is true, if the sensor is not currently in the {@link State#FAR}
+ * state, the listener will receive a {@link Listener#onFar()} callback the next time the sensor
+ * actually reaches the {@link State#FAR} state.
+ * <p>
+ * If {@code waitForFarState} is false, the listener will receive a {@link Listener#onFar()}
+ * callback immediately if the sensor is currently not in the {@link State#FAR} state.
+ * <p>
+ * This method is idempotent.
+ */
+ public void disable(boolean waitForFarState) {
+ if (mProximitySensorListener != null && mManagerEnabled) {
+ if (waitForFarState) {
+ mProximitySensorListener.unregisterWhenFar();
+ } else {
+ mProximitySensorListener.unregister();
+ }
+ mManagerEnabled = false;
+ }
+ }
+}
diff --git a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
index 5d6c7d5..cd4add6 100644
--- a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
+++ b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
@@ -237,8 +237,6 @@
if (!contactData.getStreamItems().isEmpty()) {
StreamItemEntry firstEntry = contactData.getStreamItems().get(0);
snippet = Html.fromHtml(firstEntry.getText());
- // Add quotes around the text
- snippet = context.getString(R.string.recent_updates_tab_text, snippet);
if (!firstEntry.getPhotos().isEmpty()) {
StreamItemPhotoEntry firstPhoto = firstEntry.getPhotos().get(0);
photoUri = firstPhoto.getPhotoUri();
diff --git a/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java b/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
index 106ff0e..b01316b 100644
--- a/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
+++ b/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
@@ -88,7 +88,7 @@
private View mDetailFragmentView;
private View mUpdatesFragmentView;
- private final Handler mHandler = new Handler();
+ private boolean mScrollToCurrentPage = false;
public ContactDetailFragmentCarousel(Context context) {
this(context, null);
@@ -144,6 +144,28 @@
resolveSize(screenHeight, heightMeasureSpec));
}
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ if (mScrollToCurrentPage) {
+ mScrollToCurrentPage = false;
+ // Use scrollTo() instead of smoothScrollTo() to prevent a visible flicker to the user
+ scrollTo(mCurrentPage == ABOUT_PAGE ? 0 : mAllowedHorizontalScrollLength, 0);
+ updateTouchInterceptors();
+ }
+ }
+
+ /**
+ * Set the current page that should be restored when the view is first laid out.
+ */
+ public void restoreCurrentPage(int pageIndex) {
+ setCurrentPage(pageIndex);
+ // It is only possible to scroll the view after onMeasure() has been called (where the
+ // allowed horizontal scroll length is determined). Hence, set a flag that will be read
+ // in onLayout() after the children and this view have finished being laid out.
+ mScrollToCurrentPage = true;
+ }
+
/**
* Set the current page. This auto-scrolls the carousel to the current page and dims out
* the non-selected page.
@@ -183,31 +205,13 @@
mEnableSwipe = enable;
if (mUpdatesFragmentView != null) {
mUpdatesFragmentView.setVisibility(enable ? View.VISIBLE : View.GONE);
+ mScrollToCurrentPage = true;
requestLayout();
invalidate();
}
- // This method could have been called before the view has been measured (i.e.
- // immediately after a rotation), so snap to edge only after the view is ready.
- postRunnableToSnapToEdge();
}
}
- /**
- * Snap to the currently selected page only once all the view setup and measurement has
- * completed (i.e. we need to know the allowed horizontal scroll width in order to
- * snap to the correct page).
- */
- private void postRunnableToSnapToEdge() {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- if (isAttachedToWindow() && mAboutFragment != null && mUpdatesFragment != null) {
- snapToEdge();
- }
- }
- });
- }
-
public int getCurrentPage() {
return mCurrentPage;
}
@@ -302,8 +306,4 @@
}
return false;
}
-
- private boolean isAttachedToWindow() {
- return getWindowToken() != null;
- }
}
diff --git a/src/com/android/contacts/detail/ContactDetailLayoutController.java b/src/com/android/contacts/detail/ContactDetailLayoutController.java
index 6b8829e..7a7f400 100644
--- a/src/com/android/contacts/detail/ContactDetailLayoutController.java
+++ b/src/com/android/contacts/detail/ContactDetailLayoutController.java
@@ -21,6 +21,8 @@
import com.android.contacts.R;
import com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener;
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.app.FragmentManager;
@@ -77,6 +79,7 @@
private ContactLoader.Result mContactData;
+ private boolean mTabCarouselIsAnimating;
private boolean mContactHasUpdates;
private LayoutMode mLayoutMode;
@@ -176,6 +179,7 @@
}
mTabCarousel.setListener(mTabCarouselListener);
+ mTabCarousel.restoreCurrentTab(currentPageIndex);
mDetailFragment.setVerticalScrollListener(
new VerticalScrollListener(TAB_INDEX_DETAIL));
mUpdatesFragment.setVerticalScrollListener(
@@ -211,7 +215,7 @@
mFragmentCarousel.setFragmentViews(mDetailFragmentView, mUpdatesFragmentView);
mFragmentCarousel.setFragments(mDetailFragment, mUpdatesFragment);
- mFragmentCarousel.setCurrentPage(currentPageIndex);
+ mFragmentCarousel.restoreCurrentPage(currentPageIndex);
break;
}
}
@@ -239,6 +243,7 @@
public void showEmptyState() {
switch (mLayoutMode) {
case FRAGMENT_CAROUSEL: {
+ mFragmentCarousel.setCurrentPage(0);
mFragmentCarousel.enableSwipe(false);
mDetailFragment.showEmptyState();
break;
@@ -323,6 +328,7 @@
break;
case FRAGMENT_CAROUSEL: {
// Disable swipe so only the detail fragment shows
+ mFragmentCarousel.setCurrentPage(0);
mFragmentCarousel.enableSwipe(false);
break;
}
@@ -449,12 +455,14 @@
mTabCarousel, "y", desiredValue).setDuration(75);
mTabCarouselAnimator.setInterpolator(AnimationUtils.loadInterpolator(
mActivity, android.R.anim.accelerate_decelerate_interpolator));
+ mTabCarouselAnimator.addListener(mTabCarouselAnimatorListener);
}
private void cancelTabCarouselAnimator() {
if (mTabCarouselAnimator != null) {
mTabCarouselAnimator.cancel();
mTabCarouselAnimator = null;
+ mTabCarouselIsAnimating = false;
}
}
};
@@ -478,6 +486,34 @@
}
}
+ /**
+ * This listener keeps track of whether the tab carousel animation is currently going on or not,
+ * in order to prevent other simultaneous changes to the Y position of the tab carousel which
+ * can cause flicker.
+ */
+ private final AnimatorListener mTabCarouselAnimatorListener = new AnimatorListener() {
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mTabCarouselIsAnimating = false;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mTabCarouselIsAnimating = false;
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ mTabCarouselIsAnimating = true;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mTabCarouselIsAnimating = true;
+ }
+ };
+
private final ContactDetailTabCarousel.Listener mTabCarouselListener =
new ContactDetailTabCarousel.Listener() {
@@ -529,10 +565,11 @@
int totalItemCount) {
int currentPageIndex = mViewPager.getCurrentItem();
// Don't move the carousel if: 1) the contact does not have social updates because then
- // tab carousel must not be visible, 2) if the view pager is still being scrolled, or
- // 3) if the current page being viewed is not this one.
+ // tab carousel must not be visible, 2) if the view pager is still being scrolled,
+ // 3) if the current page being viewed is not this one, or 4) if the tab carousel
+ // is already being animated vertically.
if (!mContactHasUpdates || mViewPagerState != ViewPager.SCROLL_STATE_IDLE ||
- mPageIndex != currentPageIndex) {
+ mPageIndex != currentPageIndex || mTabCarouselIsAnimating) {
return;
}
// If the FIRST item is not visible on the screen, then the carousel must be pinned
diff --git a/src/com/android/contacts/detail/ContactDetailTabCarousel.java b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
index 8a51d81..9300b54 100644
--- a/src/com/android/contacts/detail/ContactDetailTabCarousel.java
+++ b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
@@ -63,6 +63,7 @@
private int mTabDisplayLabelHeight;
+ private boolean mScrollToCurrentTab = false;
private int mLastScrollPosition;
private int mAllowedHorizontalScrollLength = Integer.MIN_VALUE;
@@ -103,12 +104,7 @@
mUpdatesTab = (CarouselTab) findViewById(R.id.tab_update);
mUpdatesTab.setLabel(mContext.getString(R.string.contactDetailUpdates));
- // TODO: We can't always assume the "about" page will be the current page.
- mAboutTab.showSelectedState();
- mAboutTab.setAlphaLayerValue(0);
mAboutTab.enableTouchInterceptor(mAboutTabTouchInterceptListener);
-
- mUpdatesTab.setAlphaLayerValue(MAX_ALPHA);
mUpdatesTab.enableTouchInterceptor(mUpdatesTabTouchInterceptListener);
// Retrieve the photo view for the "about" tab
@@ -144,6 +140,15 @@
resolveSize(tabHeight, heightMeasureSpec));
}
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ if (mScrollToCurrentTab) {
+ mScrollToCurrentTab = false;
+ scrollTo(mCurrentTab == TAB_INDEX_ABOUT ? 0 : mAllowedHorizontalScrollLength, 0);
+ }
+ }
+
private final OnClickListener mAboutTabTouchInterceptListener = new OnClickListener() {
@Override
public void onClick(View v) {
@@ -174,6 +179,17 @@
}
/**
+ * Set the current tab that should be restored when the view is first laid out.
+ */
+ public void restoreCurrentTab(int position) {
+ setCurrentTab(position);
+ // It is only possible to scroll the view after onMeasure() has been called (where the
+ // allowed horizontal scroll length is determined). Hence, set a flag that will be read
+ // in onLayout() after the children and this view have finished being laid out.
+ mScrollToCurrentTab = true;
+ }
+
+ /**
* Restore the Y position of this view to the last manually requested value. This can be done
* after the parent has been re-laid out again, where this view's position could have been
* lost if the view laid outside its parent's bounds.
@@ -225,8 +241,6 @@
* Updates the tab selection.
*/
public void setCurrentTab(int position) {
- // TODO: Handle device rotation (saving and restoring state of the selected tab)
- // This will take more work because there is no tab carousel in phone landscape
switch (position) {
case TAB_INDEX_ABOUT:
mAboutTab.showSelectedState();
@@ -270,10 +284,10 @@
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mListener.onTouchDown();
- return false;
+ return true;
case MotionEvent.ACTION_UP:
mListener.onTouchUp();
- return false;
+ return true;
}
return super.onTouchEvent(event);
}
diff --git a/src/com/android/contacts/editor/ExternalRawContactEditorView.java b/src/com/android/contacts/editor/ExternalRawContactEditorView.java
index 25bc91d..0a1ae74 100644
--- a/src/com/android/contacts/editor/ExternalRawContactEditorView.java
+++ b/src/com/android/contacts/editor/ExternalRawContactEditorView.java
@@ -27,6 +27,7 @@
import android.content.ContentUris;
import android.content.Context;
+import android.content.res.Resources;
import android.net.Uri;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Phone;
@@ -201,35 +202,42 @@
mEditExternallyButton.setVisibility(View.VISIBLE);
}
+ final Resources res = mContext.getResources();
// Phones
ArrayList<ValuesDelta> phones = state.getMimeEntries(Phone.CONTENT_ITEM_TYPE);
if (phones != null) {
- for (ValuesDelta phone : phones) {
- View field = mInflater.inflate(
- R.layout.item_read_only_field, mGeneral, false);
- TextView v;
- v = (TextView) field.findViewById(R.id.kind_title);
- v.setText(mContext.getText(R.string.phoneLabelsGroup));
- v = (TextView) field.findViewById(R.id.data);
- v.setText(PhoneNumberUtils.formatNumber(phone.getAsString(Phone.NUMBER),
+ for (int i = 0; i < phones.size(); i++) {
+ ValuesDelta phone = phones.get(i);
+ final String phoneNumber = PhoneNumberUtils.formatNumber(
+ phone.getAsString(Phone.NUMBER),
phone.getAsString(Phone.NORMALIZED_NUMBER),
- ContactsUtils.getCurrentCountryIso(getContext())));
- mGeneral.addView(field);
+ ContactsUtils.getCurrentCountryIso(getContext()));
+ final CharSequence phoneType;
+ if (phone.containsKey(Phone.TYPE)) {
+ phoneType = Phone.getTypeLabel(
+ res, phone.getAsInteger(Phone.TYPE), phone.getAsString(Phone.LABEL));
+ } else {
+ phoneType = null;
+ }
+ bindData(mContext.getText(R.string.phoneLabelsGroup),
+ phoneNumber, phoneType, i == 0);
}
}
// Emails
ArrayList<ValuesDelta> emails = state.getMimeEntries(Email.CONTENT_ITEM_TYPE);
if (emails != null) {
- for (ValuesDelta email : emails) {
- View field = mInflater.inflate(
- R.layout.item_read_only_field, mGeneral, false);
- TextView v;
- v = (TextView) field.findViewById(R.id.kind_title);
- v.setText(mContext.getText(R.string.emailLabelsGroup));
- v = (TextView) field.findViewById(R.id.data);
- v.setText(email.getAsString(Email.DATA));
- mGeneral.addView(field);
+ for (int i = 0; i < emails.size(); i++) {
+ ValuesDelta email = emails.get(i);
+ final String emailAddress = email.getAsString(Email.DATA);
+ final CharSequence emailType;
+ if (email.containsKey(Email.TYPE)) {
+ emailType = Email.getTypeLabel(
+ res, email.getAsInteger(Email.TYPE), email.getAsString(Email.LABEL));
+ } else {
+ emailType = null;
+ }
+ bindData(mContext.getText(R.string.emailLabelsGroup), emailAddress, null, i == 0);
}
}
@@ -241,6 +249,28 @@
}
}
+ private void bindData(
+ CharSequence titleText, CharSequence data, CharSequence type, boolean isFirstEntry) {
+ final View field = mInflater.inflate(R.layout.item_read_only_field, mGeneral, false);
+ if (isFirstEntry) {
+ final TextView titleView = (TextView) field.findViewById(R.id.kind_title);
+ titleView.setText(titleText);
+ } else {
+ View titleContainer = field.findViewById(R.id.kind_title_layout);
+ titleContainer.setVisibility(View.GONE);
+ }
+ final TextView dataView = (TextView) field.findViewById(R.id.data);
+ dataView.setText(data);
+ final TextView typeView = (TextView) field.findViewById(R.id.type);
+ if (!TextUtils.isEmpty(type)) {
+ typeView.setText(type);
+ } else {
+ typeView.setVisibility(View.GONE);
+ }
+
+ mGeneral.addView(field);
+ }
+
@Override
public long getRawContactId() {
return mRawContactId;
diff --git a/src/com/android/contacts/interactions/ImportExportDialogFragment.java b/src/com/android/contacts/interactions/ImportExportDialogFragment.java
index a6a37ef..078f63e 100644
--- a/src/com/android/contacts/interactions/ImportExportDialogFragment.java
+++ b/src/com/android/contacts/interactions/ImportExportDialogFragment.java
@@ -136,30 +136,32 @@
// TODO move the query into a loader and do this in a background thread
final Cursor cursor = getActivity().getContentResolver().query(Contacts.CONTENT_URI,
LOOKUP_PROJECTION, Contacts.IN_VISIBLE_GROUP + "!=0", null, null);
- try {
- if (!cursor.moveToFirst()) {
- Toast.makeText(getActivity(), R.string.share_error, Toast.LENGTH_SHORT).show();
- return;
- }
+ if (cursor != null) {
+ try {
+ if (!cursor.moveToFirst()) {
+ Toast.makeText(getActivity(), R.string.share_error, Toast.LENGTH_SHORT).show();
+ return;
+ }
- StringBuilder uriListBuilder = new StringBuilder();
- int index = 0;
- while (cursor.moveToNext()) {
- if (index != 0)
- uriListBuilder.append(':');
- uriListBuilder.append(cursor.getString(0));
- index++;
- }
- Uri uri = Uri.withAppendedPath(
- Contacts.CONTENT_MULTI_VCARD_URI,
- Uri.encode(uriListBuilder.toString()));
+ StringBuilder uriListBuilder = new StringBuilder();
+ int index = 0;
+ do {
+ if (index != 0)
+ uriListBuilder.append(':');
+ uriListBuilder.append(cursor.getString(0));
+ index++;
+ } while (cursor.moveToNext());
+ Uri uri = Uri.withAppendedPath(
+ Contacts.CONTENT_MULTI_VCARD_URI,
+ Uri.encode(uriListBuilder.toString()));
- final Intent intent = new Intent(Intent.ACTION_SEND);
- intent.setType(Contacts.CONTENT_VCARD_TYPE);
- intent.putExtra(Intent.EXTRA_STREAM, uri);
- getActivity().startActivity(intent);
- } finally {
- cursor.close();
+ final Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setType(Contacts.CONTENT_VCARD_TYPE);
+ intent.putExtra(Intent.EXTRA_STREAM, uri);
+ getActivity().startActivity(intent);
+ } finally {
+ cursor.close();
+ }
}
}
diff --git a/src/com/android/contacts/list/ContactEntryListFragment.java b/src/com/android/contacts/list/ContactEntryListFragment.java
index 528e246..df2f0cc 100644
--- a/src/com/android/contacts/list/ContactEntryListFragment.java
+++ b/src/com/android/contacts/list/ContactEntryListFragment.java
@@ -755,8 +755,6 @@
"'android.R.id.list'");
}
- mListView.setSelector(getContext().getResources().getDrawable(R.drawable.list_selector));
-
View emptyView = mView.findViewById(com.android.internal.R.id.empty);
if (emptyView != null) {
mListView.setEmptyView(emptyView);
diff --git a/src/com/android/contacts/list/ContactListFilter.java b/src/com/android/contacts/list/ContactListFilter.java
index 724098c..01d76a2 100644
--- a/src/com/android/contacts/list/ContactListFilter.java
+++ b/src/com/android/contacts/list/ContactListFilter.java
@@ -205,15 +205,13 @@
/**
* Try to obtain ContactListFilter object saved in SharedPreference.
- * If there's no info there, return custom filter instead, assuming the user wants contacts
- * which ContactsProvider remembers as "visible contacts".
- * (See also {@link Contacts#IN_VISIBLE_GROUP})
+ * If there's no info there, return ALL filter instead.
*/
public static ContactListFilter restoreDefaultPreferences(SharedPreferences prefs) {
ContactListFilter filter = restoreFromPreferences(prefs);
if (filter == null) {
- // Show contacts in IN_VISIBLE_GROUP instead.
- filter = ContactListFilter.createFilterWithType(ContactListFilter.FILTER_TYPE_CUSTOM);
+ filter = ContactListFilter.createFilterWithType(
+ ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS);
}
return filter;
}
diff --git a/src/com/android/contacts/list/ContactListItemView.java b/src/com/android/contacts/list/ContactListItemView.java
index f16102d..4b86295 100644
--- a/src/com/android/contacts/list/ContactListItemView.java
+++ b/src/com/android/contacts/list/ContactListItemView.java
@@ -24,6 +24,7 @@
import com.android.contacts.widget.TextWithHighlightingFactory;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.database.CharArrayBuffer;
import android.database.Cursor;
@@ -120,6 +121,9 @@
private TextView mCountView;
private ImageView mPresenceIcon;
+ private ColorStateList mPrimaryTextColor;
+ private ColorStateList mSecondaryTextColor;
+
private char[] mHighlightedPrefix;
private int mDefaultPhotoViewSize;
@@ -248,6 +252,9 @@
Color.GREEN));
a.recycle();
+ mPrimaryTextColor = getResources().getColorStateList(R.color.list_primary_text_color);
+ mSecondaryTextColor = getResources().getColorStateList(R.color.list_secondary_text_color);
+
mHorizontalDividerHeight = mHorizontalDividerDrawable.getIntrinsicHeight();
if (mActivatedBackgroundDrawable != null) {
@@ -409,7 +416,7 @@
mBoundsWithoutHeader.set(0, topBound, width, bottomBound);
- if (mActivatedStateSupported) {
+ if (mActivatedStateSupported && isActivated()) {
mActivatedBackgroundDrawable.setBounds(mBoundsWithoutHeader);
}
@@ -624,7 +631,7 @@
@Override
public void dispatchDraw(Canvas canvas) {
- if (mActivatedStateSupported) {
+ if (mActivatedStateSupported && isActivated()) {
mActivatedBackgroundDrawable.draw(canvas);
}
if (mHorizontalDividerVisible) {
@@ -759,6 +766,10 @@
mNameTextView.setSingleLine(true);
mNameTextView.setEllipsize(getTextEllipsis());
mNameTextView.setTextAppearance(mContext, android.R.style.TextAppearance_Medium);
+ mNameTextView.setTextColor(mPrimaryTextColor);
+ // Manually call setActivated() since this view may be added after the first
+ // setActivated() call toward this whole item view.
+ mNameTextView.setActivated(isActivated());
mNameTextView.setGravity(Gravity.CENTER_VERTICAL);
addView(mNameTextView);
}
@@ -815,6 +826,8 @@
mPhoneticNameTextView.setEllipsize(getTextEllipsis());
mPhoneticNameTextView.setTextAppearance(mContext, android.R.style.TextAppearance_Small);
mPhoneticNameTextView.setTypeface(mPhoneticNameTextView.getTypeface(), Typeface.BOLD);
+ mPhoneticNameTextView.setTextColor(mPrimaryTextColor);
+ mPhoneticNameTextView.setActivated(isActivated());
addView(mPhoneticNameTextView);
}
return mPhoneticNameTextView;
@@ -860,6 +873,8 @@
mLabelView.setEllipsize(getTextEllipsis());
mLabelView.setTextAppearance(mContext, android.R.style.TextAppearance_Small);
mLabelView.setTypeface(mLabelView.getTypeface(), Typeface.BOLD);
+ mLabelView.setTextColor(mPrimaryTextColor);
+ mLabelView.setActivated(isActivated());
addView(mLabelView);
}
return mLabelView;
@@ -890,6 +905,8 @@
mDataView.setSingleLine(true);
mDataView.setEllipsize(getTextEllipsis());
mDataView.setTextAppearance(mContext, android.R.style.TextAppearance_Small);
+ mDataView.setTextColor(mPrimaryTextColor);
+ mDataView.setActivated(isActivated());
addView(mDataView);
}
return mDataView;
@@ -919,6 +936,8 @@
mSnippetView.setEllipsize(getTextEllipsis());
mSnippetView.setTextAppearance(mContext, android.R.style.TextAppearance_Small);
mSnippetView.setTypeface(mSnippetView.getTypeface(), Typeface.BOLD);
+ mSnippetView.setTextColor(mPrimaryTextColor);
+ mSnippetView.setActivated(isActivated());
addView(mSnippetView);
}
return mSnippetView;
@@ -927,14 +946,14 @@
/**
* Returns the text view for the status, creating it if necessary.
*/
-
public TextView getStatusView() {
if (mStatusView == null) {
mStatusView = new TextView(mContext);
mStatusView.setSingleLine(true);
mStatusView.setEllipsize(getTextEllipsis());
mStatusView.setTextAppearance(mContext, android.R.style.TextAppearance_Small);
- mStatusView.setTextColor(R.color.secondary_text_color);
+ mStatusView.setTextColor(mSecondaryTextColor);
+ mStatusView.setActivated(isActivated());
addView(mStatusView);
}
return mStatusView;
diff --git a/src/com/android/contacts/list/ContactTileView.java b/src/com/android/contacts/list/ContactTileView.java
index 7355dbf..4562864 100644
--- a/src/com/android/contacts/list/ContactTileView.java
+++ b/src/com/android/contacts/list/ContactTileView.java
@@ -124,9 +124,9 @@
mQuickContact.assignContactUri(mLookupUri);
}
} else if (mQuickContact != null) {
- mQuickContact.assignContactUri(mLookupUri);
- mPhotoManager.loadPhoto(mQuickContact, entry.photoUri);
- }
+ mQuickContact.assignContactUri(mLookupUri);
+ mPhotoManager.loadPhoto(mQuickContact, entry.photoUri);
+ }
} else {
Log.w(TAG, "contactPhotoManager not set");
@@ -151,4 +151,12 @@
public interface Listener {
void onClick(ContactTileView contactTileView);
}
+
+ @Override
+ public void requestLayout() {
+ // We will assume that once measured this will not need to resize
+ // itself, so there is no need to pass the layout request to the parent
+ // view (ListView).
+ forceLayout();
+ }
}
diff --git a/src/com/android/contacts/list/DefaultContactListAdapter.java b/src/com/android/contacts/list/DefaultContactListAdapter.java
index 9a3f05e..f202522 100644
--- a/src/com/android/contacts/list/DefaultContactListAdapter.java
+++ b/src/com/android/contacts/list/DefaultContactListAdapter.java
@@ -199,11 +199,7 @@
} else {
selection.append(" AND " + RawContacts.DATA_SET + " IS NULL");
}
- // TODO (stopship): And also this private API, which is even worse
- selection.append(") OR " + Contacts._ID + "=(" +
- "SELECT contact_id " +
- "FROM raw_contacts rc inner join accounts a" +
- " ON a.profile_raw_contact_id = rc._id)");
+ selection.append(")");
break;
}
case ContactListFilter.FILTER_TYPE_GROUP: {
diff --git a/src/com/android/contacts/model/EntityDelta.java b/src/com/android/contacts/model/EntityDelta.java
index 97ab347..a045eb4 100644
--- a/src/com/android/contacts/model/EntityDelta.java
+++ b/src/com/android/contacts/model/EntityDelta.java
@@ -561,6 +561,11 @@
return mAfter;
}
+ public boolean containsKey(String key) {
+ return ((mAfter != null && mAfter.containsKey(key)) ||
+ (mBefore != null && mBefore.containsKey(key)));
+ }
+
public String getAsString(String key) {
if (mAfter != null && mAfter.containsKey(key)) {
return mAfter.getAsString(key);
diff --git a/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java b/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java
index 7d29406..8d549a7 100644
--- a/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java
+++ b/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java
@@ -20,6 +20,7 @@
import static com.android.contacts.CallDetailActivity.EXTRA_VOICEMAIL_URI;
import com.android.common.io.MoreCloseables;
+import com.android.contacts.ProximitySensorAware;
import com.android.contacts.R;
import com.android.contacts.util.AsyncTaskExecutors;
import com.android.ex.variablespeed.MediaPlayerProxy;
@@ -36,6 +37,7 @@
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
+import android.os.PowerManager;
import android.provider.VoicemailContract;
import android.util.Log;
import android.view.LayoutInflater;
@@ -91,10 +93,15 @@
Uri voicemailUri = arguments.getParcelable(EXTRA_VOICEMAIL_URI);
Preconditions.checkNotNull(voicemailUri, "fragment must contain EXTRA_VOICEMAIL_URI");
boolean startPlayback = arguments.getBoolean(EXTRA_VOICEMAIL_START_PLAYBACK, false);
+ PowerManager powerManager =
+ (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE);
+ PowerManager.WakeLock wakeLock =
+ powerManager.newWakeLock(
+ PowerManager.SCREEN_DIM_WAKE_LOCK, getClass().getSimpleName());
mPresenter = new VoicemailPlaybackPresenter(createPlaybackViewImpl(),
createMediaPlayer(mScheduledExecutorService), voicemailUri,
mScheduledExecutorService, startPlayback,
- AsyncTaskExecutors.createAsyncTaskExecutor());
+ AsyncTaskExecutors.createAsyncTaskExecutor(), wakeLock);
mPresenter.onCreate(savedInstanceState);
}
@@ -263,6 +270,24 @@
}
@Override
+ public void enableProximitySensor() {
+ // Only change the state if the activity is still around.
+ Activity activity = mActivityReference.get();
+ if (activity != null && activity instanceof ProximitySensorAware) {
+ ((ProximitySensorAware) activity).enableProximitySensor();
+ }
+ }
+
+ @Override
+ public void disableProximitySensor() {
+ // Only change the state if the activity is still around.
+ Activity activity = mActivityReference.get();
+ if (activity != null && activity instanceof ProximitySensorAware) {
+ ((ProximitySensorAware) activity).disableProximitySensor(true);
+ }
+ }
+
+ @Override
public void registerContentObserver(Uri uri, ContentObserver observer) {
mApplicationContext.getContentResolver().registerContentObserver(uri, false, observer);
}
@@ -370,7 +395,6 @@
@Override
public void setSpeakerPhoneOn(boolean on) {
- getAudioManager().setMode(AudioManager.MODE_IN_CALL);
getAudioManager().setSpeakerphoneOn(on);
if (on) {
mPlaybackSpeakerphone.setImageResource(R.drawable.ic_sound_holo_dark);
@@ -378,6 +402,14 @@
mPlaybackSpeakerphone.setImageResource(R.drawable.ic_sound_holo_dark);
}
}
+
+ @Override
+ public void setVolumeControlStream(int streamType) {
+ Activity activity = mActivityReference.get();
+ if (activity != null) {
+ activity.setVolumeControlStream(streamType);
+ }
+ }
}
/**
diff --git a/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java b/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
index d54cddc..f8e497d 100644
--- a/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
+++ b/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
@@ -27,11 +27,13 @@
import android.content.Context;
import android.database.ContentObserver;
+import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
+import android.os.PowerManager;
import android.view.View;
import android.widget.SeekBar;
@@ -59,6 +61,9 @@
@NotThreadSafe
@VisibleForTesting
public class VoicemailPlaybackPresenter {
+ /** The stream used to playback voicemail. */
+ private static final int PLAYBACK_STREAM = AudioManager.STREAM_VOICE_CALL;
+
/** Contract describing the behaviour we need from the ui we are controlling. */
public interface PlaybackView {
Context getDataSourceContext();
@@ -86,6 +91,9 @@
void setFetchContentTimeout();
void registerContentObserver(Uri uri, ContentObserver observer);
void unregisterContentObserver(ContentObserver observer);
+ void enableProximitySensor();
+ void disableProximitySensor();
+ void setVolumeControlStream(int streamType);
}
/** The enumeration of {@link AsyncTask} objects we use in this class. */
@@ -160,19 +168,23 @@
* This variable is thread-contained, accessed only on the ui thread.
*/
private FetchResultHandler mFetchResultHandler;
+ private PowerManager.WakeLock mWakeLock;
public VoicemailPlaybackPresenter(PlaybackView view, MediaPlayerProxy player,
Uri voicemailUri, ScheduledExecutorService executorService,
- boolean startPlayingImmediately, AsyncTaskExecutor asyncTaskExecutor) {
+ boolean startPlayingImmediately, AsyncTaskExecutor asyncTaskExecutor,
+ PowerManager.WakeLock wakeLock) {
mView = view;
mPlayer = player;
mVoicemailUri = voicemailUri;
mStartPlayingImmediately = startPlayingImmediately;
mAsyncTaskExecutor = asyncTaskExecutor;
mPositionUpdater = new PositionUpdater(executorService, SLIDER_UPDATE_PERIOD_MILLIS);
+ mWakeLock = wakeLock;
}
public void onCreate(Bundle bundle) {
+ mView.setVolumeControlStream(PLAYBACK_STREAM);
checkThatWeHaveContent();
}
@@ -298,6 +310,7 @@
try {
mPlayer.reset();
mPlayer.setDataSource(mView.getDataSourceContext(), mVoicemailUri);
+ mPlayer.setAudioStreamType(PLAYBACK_STREAM);
mPlayer.prepare();
return null;
} catch (IOException e) {
@@ -334,6 +347,8 @@
mView.setRateIncreaseButtonListener(createRateIncreaseListener());
mView.setClipPosition(0, mPlayer.getDuration());
mView.playbackStopped();
+ // Always disable on stop.
+ mView.disableProximitySensor();
if (mStartPlayingImmediately) {
resetPrepareStartPlaying(0);
}
@@ -348,16 +363,16 @@
}
}
- /**
- * This method should be called <b>only on the ui thread</b>.
- */
public void onDestroy() {
+ mPlayer.release();
if (mFetchResultHandler != null) {
mFetchResultHandler.destroy();
mFetchResultHandler = null;
}
mPositionUpdater.stopUpdating();
- mPlayer.release();
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
}
private class MediaPlayerErrorListener implements MediaPlayer.OnErrorListener {
@@ -420,6 +435,7 @@
try {
mPlayer.reset();
mPlayer.setDataSource(mView.getDataSourceContext(), mVoicemailUri);
+ mPlayer.setAudioStreamType(PLAYBACK_STREAM);
mPlayer.prepare();
mDuration.set(mPlayer.getDuration());
int startPosition = constrain(clipPositionInMillis, 0, mDuration.get());
@@ -427,6 +443,13 @@
mPlayer.seekTo(startPosition);
mPlayer.start();
mView.playbackStarted();
+ if (!mWakeLock.isHeld()) {
+ mWakeLock.acquire();
+ }
+ // Only enable if we are not currently using the speaker phone.
+ if (!mView.isSpeakerPhoneOn()) {
+ mView.enableProximitySensor();
+ }
mPositionUpdater.startUpdating(startPosition, mDuration.get());
} catch (IOException e) {
handleError(e);
@@ -446,6 +469,11 @@
private void stopPlaybackAtPosition(int clipPosition, int duration) {
mPositionUpdater.stopUpdating();
mView.playbackStopped();
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
+ // Always disable on stop.
+ mView.disableProximitySensor();
mView.setClipPosition(clipPosition, duration);
if (mPlayer.isPlaying()) {
mPlayer.pause();
@@ -489,7 +517,16 @@
private class SpeakerphoneListener implements View.OnClickListener {
@Override
public void onClick(View v) {
- mView.setSpeakerPhoneOn(!mView.isSpeakerPhoneOn());
+ boolean previousState = mView.isSpeakerPhoneOn();
+ mView.setSpeakerPhoneOn(!previousState);
+ if (mPlayer.isPlaying() && previousState) {
+ // If we are currently playing and we are disabling the speaker phone, enable the
+ // sensor.
+ mView.enableProximitySensor();
+ } else {
+ // If we are not currently playing, disable the sensor.
+ mView.disableProximitySensor();
+ }
}
}
@@ -560,5 +597,8 @@
if (mPlayer.isPlaying()) {
stopPlaybackAtPosition(mPlayer.getCurrentPosition(), mDuration.get());
}
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
}
}
diff --git a/src/com/android/contacts/voicemail/VoicemailStatusHelperImpl.java b/src/com/android/contacts/voicemail/VoicemailStatusHelperImpl.java
index 9e481f8..d88b5d3 100644
--- a/src/com/android/contacts/voicemail/VoicemailStatusHelperImpl.java
+++ b/src/com/android/contacts/voicemail/VoicemailStatusHelperImpl.java
@@ -221,8 +221,13 @@
Uri actionUri = null;
if (action == Action.CALL_VOICEMAIL) {
actionUri = UriUtils.parseUriOrNull(cursor.getString(VOICEMAIL_ACCESS_URI_INDEX));
+ // Even if actionUri is null, it is still be useful to show the notification.
} else if (action == Action.CONFIGURE_VOICEMAIL) {
actionUri = UriUtils.parseUriOrNull(cursor.getString(SETTINGS_URI_INDEX));
+ // If there is no settings URI, there is no point in showing the notification.
+ if (actionUri == null) {
+ return null;
+ }
}
return new MessageStatusWithPriority(
new StatusMessage(sourcePackage, overallState.getCallLogMessageId(),