Merge "Change tab carousel tab size according to device size"
diff --git a/proguard.flags b/proguard.flags
index 577144b..5a08b9f 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -2,6 +2,13 @@
public <init>(...);
}
+# Xml files containing onClick (menus and layouts) require that proguard not
+# remove their handlers.
+-keepclassmembers class * extends android.app.Activity {
+ public void *(android.view.View);
+ public void *(android.view.MenuItem);
+}
+
# TODO: Instead of keeping the following two functions we could as well just remove them completely
# as they are only used in test code
@@ -16,4 +23,4 @@
# Any methods whose name is '*ForTest' are preserved.
-keep class ** {
*** *ForTest(...);
-}
\ No newline at end of file
+}
diff --git a/res/drawable-hdpi/ic_share_holo_dark.png b/res/drawable-hdpi/ic_share_holo_dark.png
new file mode 100644
index 0000000..686da4c
--- /dev/null
+++ b/res/drawable-hdpi/ic_share_holo_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_share_holo_dark.png b/res/drawable-mdpi/ic_share_holo_dark.png
new file mode 100644
index 0000000..5c33eac
--- /dev/null
+++ b/res/drawable-mdpi/ic_share_holo_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_share_holo_dark.png b/res/drawable-xhdpi/ic_share_holo_dark.png
new file mode 100644
index 0000000..b3e2f80
--- /dev/null
+++ b/res/drawable-xhdpi/ic_share_holo_dark.png
Binary files differ
diff --git a/res/layout-sw580dp-w1000dp/contact_detail_list_item.xml b/res/layout-sw580dp-w1000dp/contact_detail_list_item.xml
index 4cb4096..b57e85c 100644
--- a/res/layout-sw580dp-w1000dp/contact_detail_list_item.xml
+++ b/res/layout-sw580dp-w1000dp/contact_detail_list_item.xml
@@ -42,7 +42,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
- android:paddingLeft="12dip"
+ android:paddingLeft="8dip"
android:orientation="vertical">
<TextView
@@ -56,6 +56,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"
android:visibility="gone" />
</LinearLayout>
@@ -68,37 +69,27 @@
android:gravity="center"
android:scaleType="centerInside" />
- <FrameLayout
+ <TextView
+ android:id="@+id/kind"
android:layout_width="wrap_content"
- android:layout_height="@dimen/detail_min_line_item_height"
- android:paddingLeft="@dimen/detail_item_side_margin"
- android:paddingRight="@dimen/detail_item_side_margin">
+ android:layout_height="wrap_content"
+ android:visibility="gone" />
- <TextView
- android:id="@+id/kind"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="gone" />
+ <TextView
+ android:id="@+id/type"
+ style="@style/ContactDetailItemType"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingRight="16dip" />
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:orientation="horizontal">
+ <View
+ android:id="@+id/primary_indicator"
+ android:layout_width="16dip"
+ android:layout_height="16dip"
+ android:visibility="gone"
+ android:layout_gravity="center_vertical"
+ android:background="@drawable/ic_menu_mark" />
- <TextView
- android:id="@+id/type"
- style="@style/ContactDetailItemType" />
-
- <View
- android:id="@+id/primary_indicator"
- android:layout_width="16dip"
- android:layout_height="16dip"
- android:visibility="gone"
- android:layout_gravity="center_vertical"
- android:background="@drawable/ic_menu_mark" />
-
- </LinearLayout>
- </FrameLayout>
</com.android.contacts.detail.PrimaryActionViewContainer>
<View
diff --git a/res/layout-sw580dp-w1000dp/detail_header_contact_with_updates.xml b/res/layout-sw580dp-w1000dp/detail_header_contact_with_updates.xml
index dce00ac..6ce811f 100644
--- a/res/layout-sw580dp-w1000dp/detail_header_contact_with_updates.xml
+++ b/res/layout-sw580dp-w1000dp/detail_header_contact_with_updates.xml
@@ -52,7 +52,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
- android:textAppearance="?android:attr/textAppearanceMedium" />
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorSecondary" />
<CheckBox
android:id="@+id/star"
diff --git a/res/layout-sw580dp-w1000dp/detail_header_contact_without_updates.xml b/res/layout-sw580dp-w1000dp/detail_header_contact_without_updates.xml
index 486b7c2..be82d88 100644
--- a/res/layout-sw580dp-w1000dp/detail_header_contact_without_updates.xml
+++ b/res/layout-sw580dp-w1000dp/detail_header_contact_without_updates.xml
@@ -36,7 +36,8 @@
android:id="@+id/company"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium" />
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorSecondary" />
<CheckBox
android:id="@+id/star"
diff --git a/res/layout-sw580dp/detail_header_contact_with_updates.xml b/res/layout-sw580dp/detail_header_contact_with_updates.xml
index c239e40..6b6f02b 100644
--- a/res/layout-sw580dp/detail_header_contact_with_updates.xml
+++ b/res/layout-sw580dp/detail_header_contact_with_updates.xml
@@ -54,7 +54,8 @@
android:id="@+id/company"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium" />
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorSecondary" />
<CheckBox
android:id="@+id/star"
@@ -64,4 +65,4 @@
android:contentDescription="@string/description_star"
style="?android:attr/starStyle" />
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/res/layout-sw580dp/detail_header_contact_without_updates.xml b/res/layout-sw580dp/detail_header_contact_without_updates.xml
index 3bc8e67..995e8f7 100644
--- a/res/layout-sw580dp/detail_header_contact_without_updates.xml
+++ b/res/layout-sw580dp/detail_header_contact_without_updates.xml
@@ -68,7 +68,8 @@
android:id="@+id/company"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium" />
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorSecondary" />
<CheckBox
android:id="@+id/star"
@@ -78,4 +79,4 @@
android:contentDescription="@string/description_star"
style="?android:attr/starStyle" />
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/res/layout/call_detail_history_item.xml b/res/layout/call_detail_history_item.xml
index 069ade9..b225369 100644
--- a/res/layout/call_detail_history_item.xml
+++ b/res/layout/call_detail_history_item.xml
@@ -22,7 +22,8 @@
android:background="?attr/call_log_secondary_background_color"
android:padding="@dimen/call_log_indent_margin"
>
- <FrameLayout
+ <view
+ class="com.android.contacts.calllog.CallTypeIconsView"
android:id="@+id/call_type_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/res/layout/call_log_list_item.xml b/res/layout/call_log_list_item.xml
index a86d839..3b5601f 100644
--- a/res/layout/call_log_list_item.xml
+++ b/res/layout/call_log_list_item.xml
@@ -14,60 +14,41 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:padding="@dimen/call_log_inner_margin"
>
<!--
- We have a nested FrameLayout because the margin attributes out the outer
- layout are not used when this layout is inflated within a list.
+ This layout may represent either a call log item or one of the
+ headers in the call log.
- TODO: Can we find a way to avoid the extra layer?
- -->
- <FrameLayout
+ The former will make the @id/call_log_item visible and the
+ @id/call_log_header gone.
+
+ The latter will make the @id/call_log_header visible and the
+ @id/call_log_item gone
+ -->
+
+ <RelativeLayout
+ android:id="@+id/call_log_item"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ >
+ <include layout="@layout/call_log_contact_photo"/>
+ <include layout="@layout/call_log_action_call"/>
+ <include layout="@layout/call_log_list_item_layout"/>
+ </RelativeLayout>
+
+ <TextView
+ android:id="@+id/call_log_header_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/call_log_inner_margin"
- android:layout_marginRight="@dimen/call_log_inner_margin"
- android:layout_marginTop="@dimen/call_log_inner_margin"
- android:layout_marginBottom="@dimen/call_log_inner_margin"
- >
- <!--
- This layout may represent either a call log item or one of the
- headers in the call log.
-
- The former will make the @id/call_log_item visible and the
- @id/call_log_header gone.
-
- The latter will make the @id/call_log_header visible and the
- @id/call_log_item gone
- -->
-
- <RelativeLayout
- android:id="@+id/call_log_item"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- >
- <include layout="@layout/call_log_contact_photo"/>
- <include layout="@layout/call_log_action_call"/>
- <include layout="@layout/call_log_list_item_layout"/>
- </RelativeLayout>
-
- <LinearLayout
- android:id="@+id/call_log_header"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- >
- <TextView
- android:id="@+id/call_log_header_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/call_log_inner_margin"
- android:textSize="14sp"
- android:textStyle="bold"
- android:textColor="?attr/call_log_header_color"
- />
- </LinearLayout>
- </FrameLayout>
-</LinearLayout>
+ android:textSize="14sp"
+ android:textStyle="bold"
+ android:textColor="?attr/call_log_header_color"
+ />
+</FrameLayout>
diff --git a/res/layout/call_log_phone_call_details.xml b/res/layout/call_log_phone_call_details.xml
index 5a4131e..4d12a1d 100644
--- a/res/layout/call_log_phone_call_details.xml
+++ b/res/layout/call_log_phone_call_details.xml
@@ -45,13 +45,13 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
>
- <LinearLayout
+ <view
+ class="com.android.contacts.calllog.CallTypeIconsView"
android:id="@+id/call_type_icons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/call_log_icon_margin"
android:layout_gravity="center_vertical"
- android:orientation="horizontal"
/>
<TextView
android:id="@+id/call_type_name"
diff --git a/res/layout/contact_detail_list_item.xml b/res/layout/contact_detail_list_item.xml
index 205bc81..e2818e9 100644
--- a/res/layout/contact_detail_list_item.xml
+++ b/res/layout/contact_detail_list_item.xml
@@ -24,6 +24,8 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
+ android:paddingTop="12dip"
+ android:paddingBottom="12dip"
android:minHeight="@dimen/detail_min_line_item_height">
<!-- Note: padding might be controlled programatically -->
@@ -64,7 +66,9 @@
<TextView
android:id="@+id/type"
- style="@style/ContactDetailItemType" />
+ style="@style/ContactDetailItemType"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
<View
android:id="@+id/primary_indicator"
@@ -82,6 +86,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"
android:visibility="gone" />
</LinearLayout>
diff --git a/res/layout/contact_detail_network_title_entry_view.xml b/res/layout/contact_detail_network_title_entry_view.xml
index 2cede93..bc0d3f1 100644
--- a/res/layout/contact_detail_network_title_entry_view.xml
+++ b/res/layout/contact_detail_network_title_entry_view.xml
@@ -32,6 +32,8 @@
android:id="@+id/network_icon"
android:layout_width="@dimen/detail_network_icon_size"
android:layout_height="@dimen/detail_network_icon_size"
+ android:layout_marginLeft="@dimen/detail_item_icon_margin"
+ android:layout_marginRight="@dimen/detail_item_icon_margin"
android:layout_gravity="center_vertical"
android:scaleType="centerInside" />
@@ -39,7 +41,6 @@
android:id="@+id/network_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/detail_item_side_margin"
android:layout_gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceMedium" />
diff --git a/res/layout/contact_tile_starred_secondary_target.xml b/res/layout/contact_tile_starred_secondary_target.xml
index 4b2639b..887fa5d 100644
--- a/res/layout/contact_tile_starred_secondary_target.xml
+++ b/res/layout/contact_tile_starred_secondary_target.xml
@@ -33,18 +33,42 @@
android:layout_width="match_parent"
android:layout_height="@dimen/contact_tile_shadowbox_height"
android:layout_alignParentBottom="true"
+ android:layout_alignParentLeft="true"
style="@style/ContactTileStarredShadowBox" />
- <TextView
- android:id="@+id/contact_tile_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ <FrameLayout
+ android:id="@+id/contact_tile_info_layout"
+ android:layout_height="@dimen/contact_tile_shadowbox_height"
+ android:layout_width="wrap_content"
+ android:orientation="horizontal"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginLeft="8dip"
- android:layout_marginBottom="20dip"
- android:textColor="@android:color/white"
- stlye="@style/ContactTileStarredName" />
+ android:layout_marginRight="45dip">
+
+ <TextView
+ android:id="@+id/contact_tile_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:textColor="@android:color/white"
+ android:singleLine="true"
+ android:textSize="16sp"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="3dip"
+ android:ellipsize="marquee" />
+
+ </FrameLayout>
+
+ <View
+ android:id="@+id/vertical_divider"
+ android:layout_width="1dip"
+ android:layout_height="24dip"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentRight="true"
+ android:layout_marginBottom="12dip"
+ android:layout_marginRight="44dip"
+ android:background="?android:attr/dividerVertical" />
<ImageButton
android:id="@+id/contact_tile_push_state"
@@ -57,9 +81,11 @@
android:src="@drawable/ic_tab_unselected_contacts"
android:background="?android:attr/selectableItemBackground"
android:layout_height="@dimen/contact_tile_shadowbox_height"
- android:layout_width="wrap_content"
+ android:layout_width="32dip"
android:layout_alignParentBottom="true"
- android:layout_alignParentRight="true" />
+ android:layout_alignParentRight="true"
+ android:layout_marginLeft="8dip"
+ android:layout_marginRight="8dip" />
</RelativeLayout>
diff --git a/res/layout/group_browse_list_item.xml b/res/layout/group_browse_list_item.xml
index ecdc132..b9b272c 100644
--- a/res/layout/group_browse_list_item.xml
+++ b/res/layout/group_browse_list_item.xml
@@ -19,6 +19,8 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:minHeight="@dimen/detail_min_line_item_height"
+ android:paddingRight="20dip"
android:paddingBottom="10dip"
style="@style/GroupBrowseListItem">
@@ -37,25 +39,76 @@
layout="@layout/group_browse_list_account_header"
android:visibility="gone" />
- <TextView
- android:id="@+id/label"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:paddingLeft="10dip"
- android:paddingRight="10dip"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:ellipsize="end"
- android:singleLine="true" />
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
- <TextView
- android:id="@+id/count"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:paddingLeft="10dip"
- android:paddingRight="10dip"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorTertiary"
- android:ellipsize="end"
- android:singleLine="true" />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_toLeftOf="@+id/icons"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true">
+ <TextView
+ android:id="@+id/label"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:paddingLeft="10dip"
+ android:paddingRight="10dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:ellipsize="end"
+ android:singleLine="true" />
+
+ <TextView
+ android:id="@+id/count"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:paddingLeft="10dip"
+ android:paddingRight="10dip"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorTertiary"
+ android:ellipsize="end"
+ android:singleLine="true" />
+
+ </LinearLayout>
+
+ <TableLayout
+ android:id="@+id/icons"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true">
+ <TableRow
+ android:layout_marginBottom="1dip">
+ <ImageView
+ android:id="@+id/icon_1"
+ android:layout_width="@dimen/group_list_icon_size"
+ android:layout_height="@dimen/group_list_icon_size"
+ android:layout_marginRight="1dip"
+ android:src="@drawable/ic_contact_picture" />
+ <ImageView
+ android:id="@+id/icon_2"
+ android:layout_width="@dimen/group_list_icon_size"
+ android:layout_height="@dimen/group_list_icon_size"
+ android:src="@drawable/ic_contact_picture" />
+ </TableRow>
+ <TableRow>
+ <ImageView
+ android:id="@+id/icon_3"
+ android:layout_width="@dimen/group_list_icon_size"
+ android:layout_height="@dimen/group_list_icon_size"
+ android:layout_marginRight="1dip"
+ android:src="@drawable/ic_contact_picture" />
+ <ImageView
+ android:id="@+id/icon_4"
+ android:layout_width="@dimen/group_list_icon_size"
+ android:layout_height="@dimen/group_list_icon_size"
+ android:src="@drawable/ic_contact_picture" />
+ </TableRow>
+
+ </TableLayout>
+ </RelativeLayout>
</LinearLayout>
+
diff --git a/res/layout/playback_layout.xml b/res/layout/playback_layout.xml
index 1fb36be..020c017 100644
--- a/res/layout/playback_layout.xml
+++ b/res/layout/playback_layout.xml
@@ -40,18 +40,6 @@
android:src="@drawable/ic_hold_pause_holo_dark"
android:layout_weight="1"
/>
- <ImageButton
- android:id="@+id/playback_trash"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="5px"
- android:layout_marginTop="4dip"
- android:layout_marginLeft="4dip"
- android:layout_marginRight="4dip"
- android:background="@drawable/dialpad_background"
- android:src="@drawable/ic_trash_holo_dark"
- android:layout_weight="1"
- />
</LinearLayout>
<SeekBar
android:id="@+id/playback_seek"
diff --git a/res/menu/call_details_options.xml b/res/menu/call_details_options.xml
index 68e265c..0db32a4 100644
--- a/res/menu/call_details_options.xml
+++ b/res/menu/call_details_options.xml
@@ -15,15 +15,26 @@
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
- android:id="@+id/remove_from_call_log"
+ android:id="@+id/menu_share_voicemail"
+ android:icon="@drawable/ic_share_holo_dark"
+ android:showAsAction="ifRoom"
+ android:onClick="onMenuShareVoicemail"
+ />
+ <item
+ android:id="@+id/menu_trash"
+ android:icon="@drawable/ic_trash_holo_dark"
+ android:showAsAction="ifRoom"
+ android:onClick="onMenuTrashVoicemail"
+ />
+ <item
+ android:id="@+id/menu_remove_from_call_log"
android:icon="@android:drawable/ic_menu_close_clear_cancel"
android:title="@string/recentCalls_removeFromRecentList"
- android:showAsAction="withText"
+ android:onClick="onMenuRemoveFromCallLog"
/>
-
<item
- android:id="@+id/edit_number_before_call"
+ android:id="@+id/menu_edit_number_before_call"
android:title="@string/recentCalls_editNumberBeforeCall"
- android:showAsAction="withText"
+ android:onClick="onMenuEditNumberBeforeCall"
/>
</menu>
diff --git a/res/values-sw580dp-w720dp/styles.xml b/res/values-sw580dp-w720dp/styles.xml
index d4487b2..4de10b6 100644
--- a/res/values-sw580dp-w720dp/styles.xml
+++ b/res/values-sw580dp-w720dp/styles.xml
@@ -16,6 +16,8 @@
<resources>
<style name="PeopleTheme" parent="@android:style/Theme.Holo.Light.SolidActionBar.Inverse.SplitActionBarWhenNarrow">
<item name="android:actionBarStyle">@style/ContactsActionBarStyle</item>
+ <item name="android:textColorPrimary">@color/primary_text_color</item>
+ <item name="android:textColorSecondary">@color/secondary_text_color</item>
<item name="list_item_height">66dip</item>
<item name="activated_background">@drawable/list_item_activated_background</item>
<item name="android:windowContentOverlay">@null</item>
diff --git a/res/values-sw580dp/dimens.xml b/res/values-sw580dp/dimens.xml
index a10d234..ab630d2 100644
--- a/res/values-sw580dp/dimens.xml
+++ b/res/values-sw580dp/dimens.xml
@@ -23,6 +23,8 @@
<dimen name="editor_field_top_padding">12dip</dimen>
<dimen name="editor_field_bottom_padding">12dip</dimen>
<dimen name="detail_item_side_margin">0dip</dimen>
+ <dimen name="detail_item_vertical_margin">16dip</dimen>
+ <dimen name="detail_item_icon_margin">8dip</dimen>
<dimen name="contact_name_text_size">26sp</dimen>
<dimen name="action_bar_filter_min_width">120dip</dimen>
<dimen name="action_bar_filter_max_width">120dip</dimen>
diff --git a/res/values-sw580dp/styles.xml b/res/values-sw580dp/styles.xml
index cf4c4ee..256683a 100644
--- a/res/values-sw580dp/styles.xml
+++ b/res/values-sw580dp/styles.xml
@@ -16,6 +16,8 @@
<resources>
<style name="PeopleTheme" parent="@android:style/Theme.Holo.Light.SolidActionBar.Inverse.SplitActionBarWhenNarrow">
<item name="android:actionBarStyle">@style/ContactsActionBarStyle</item>
+ <item name="android:textColorPrimary">@color/primary_text_color</item>
+ <item name="android:textColorSecondary">@color/secondary_text_color</item>
<item name="list_item_height">66dip</item>
<item name="activated_background">@drawable/list_item_activated_background</item>
<item name="android:windowContentOverlay">@null</item>
@@ -103,17 +105,6 @@
<item name="android:windowIsFloating">true</item>
</style>
- <style name="ContactDetailItemType">
- <item name="android:layout_width">match_parent</item>
- <item name="android:layout_height">match_parent</item>
- <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
- <item name="android:textColor">?android:attr/textColorTertiary</item>
- <item name="android:singleLine">true</item>
- <item name="android:ellipsize">marquee</item>
- <item name="android:gravity">center_vertical</item>
- <item name="android:paddingTop">5dip</item>
- </style>
-
<style name="GroupBrowseListItem">
<item name="android:background">@drawable/list_item_activated_background</item>
</style>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index b6b3f31..552d47b 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -85,6 +85,12 @@
<!-- Color of the theme of the People app -->
<color name="people_app_theme_color">#33B5E5</color>
+ <!-- Primary text color in the People app -->
+ <color name="primary_text_color">#333333</color>
+
+ <!-- Secondary text color in the People app -->
+ <color name="secondary_text_color">#777777</color>
+
<!-- Colors in the contact browser list -->
<color name="contact_browser_list_bk_color">#EEEEEE</color>
<color name="contact_count_text_color">#777777</color>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 569f00b..a4a6112 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -173,6 +173,9 @@
<!-- Border padding for the group list header for each account -->
<dimen name="group_list_header_padding">5dip</dimen>
+ <!-- Size of group list icons -->
+ <dimen name="group_list_icon_size">32dip</dimen>
+
<!-- Border padding for the group detail fragment header -->
<dimen name="group_detail_border_padding">20dip</dimen>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index dc22fd8..58374ce 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -58,7 +58,7 @@
<item name="favorites_padding_bottom">?android:attr/actionBarSize</item>
</style>
- <style name="CallDetailActivityTheme" parent="android:Theme.Holo.SplitActionBarWhenNarrow">
+ <style name="CallDetailActivityTheme" parent="android:Theme.Holo">
<item name="android:windowBackground">@android:color/black</item>
<item name="android:gravity">top</item>
<!-- CallLog -->
@@ -76,6 +76,8 @@
<style name="ContactDetailActivityTheme" parent="@android:style/Theme.Holo.Light.SolidActionBar.Inverse">
<item name="android:actionBarStyle">@style/ContactsActionBarStyle</item>
<item name="android:windowContentOverlay">@null</item>
+ <item name="android:textColorPrimary">@color/primary_text_color</item>
+ <item name="android:textColorSecondary">@color/secondary_text_color</item>
</style>
<style name="ContactEditorActivityTheme" parent="@android:style/Theme.Holo.Light.SolidActionBar.Inverse.SplitActionBarWhenNarrow">
<item name="android:actionBarStyle">@style/ContactsActionBarStyle</item>
@@ -117,6 +119,8 @@
<style name="PeopleTheme" parent="@android:style/Theme.Holo.Light.SolidActionBar.Inverse.SplitActionBarWhenNarrow">
<item name="android:actionBarStyle">@style/ContactsActionBarStyle</item>
+ <item name="android:textColorPrimary">@color/primary_text_color</item>
+ <item name="android:textColorSecondary">@color/secondary_text_color</item>
<item name="list_item_height">?android:attr/listPreferredItemHeight</item>
<item name="activated_background">@drawable/list_item_activated_background</item>
<item name="section_header_background">@drawable/list_title_holo</item>
@@ -154,6 +158,8 @@
<!-- TODO: Clean up this file so themes aren't copied. -->
<style name="GroupDetailTheme" parent="@android:style/Theme.Holo.Light.SolidActionBar.Inverse.SplitActionBarWhenNarrow">
<item name="android:actionBarStyle">@style/ContactsActionBarStyle</item>
+ <item name="android:textColorPrimary">@color/primary_text_color</item>
+ <item name="android:textColorSecondary">@color/secondary_text_color</item>
<item name="list_item_height">?android:attr/listPreferredItemHeight</item>
<item name="activated_background">@drawable/list_item_activated_background</item>
<item name="section_header_background">@drawable/list_title_holo</item>
@@ -238,17 +244,14 @@
</style>
<style name="ContactDetailItemType">
- <item name="android:layout_width">wrap_content</item>
- <item name="android:layout_height">wrap_content</item>
<item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
- <item name="android:textColor">?android:attr/textColorTertiary</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:singleLine">true</item>
<item name="android:ellipsize">marquee</item>
- <item name="android:gravity">center_vertical</item>
+ <item name="android:layout_gravity">center_vertical</item>
</style>
<style name="GroupBrowseListItem">
- <item name="android:paddingRight">20dip</item>
</style>
<style name="DialtactsDigitsTextAppearance">
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index a46d2e2..d0eb817 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -102,8 +102,6 @@
private TextView mStatusMessageText;
private TextView mStatusMessageAction;
- /** Whether we should show "remove from call log" in the options menu. */
- private boolean mHasRemoveFromCallLog;
/** Whether we should show "edit number before call" in the options menu. */
private boolean mHasEditNumberBeforeCall;
@@ -148,7 +146,7 @@
mResources = getResources();
mPhoneCallDetailsViews = PhoneCallDetailsViews.fromView(getWindow().getDecorView());
- mCallTypeHelper = new CallTypeHelper(getResources(), mInflater);
+ mCallTypeHelper = new CallTypeHelper(getResources());
mPhoneNumberHelper = new PhoneNumberHelper(mResources, getVoicemailNumber());
mPhoneCallDetailsHelper = new PhoneCallDetailsHelper(mResources, mCallTypeHelper,
mPhoneNumberHelper);
@@ -353,9 +351,6 @@
getString(R.string.menu_sendTextMessage), smsIntent));
}
- // This action deletes all elements in the group from the call log.
- // We don't have this action for voicemails, because you can just use the trash button.
- mHasRemoveFromCallLog = !hasVoicemail();
mHasEditNumberBeforeCall = canPlaceCallsTo && !isSipNumber && !isVoicemailNumber;
if (actions.size() != 0) {
@@ -614,58 +609,65 @@
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.call_details_options, menu);
- return true;
+ return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// This action deletes all elements in the group from the call log.
// We don't have this action for voicemails, because you can just use the trash button.
- menu.findItem(R.id.remove_from_call_log).setVisible(mHasRemoveFromCallLog);
- menu.findItem(R.id.edit_number_before_call).setVisible(mHasEditNumberBeforeCall);
- return mHasRemoveFromCallLog || mHasEditNumberBeforeCall;
+ menu.findItem(R.id.menu_remove_from_call_log).setVisible(!hasVoicemail());
+ menu.findItem(R.id.menu_edit_number_before_call).setVisible(mHasEditNumberBeforeCall);
+ menu.findItem(R.id.menu_trash).setVisible(hasVoicemail());
+ menu.findItem(R.id.menu_share_voicemail).setVisible(hasVoicemail());
+ return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
switch (item.getItemId()) {
- case R.id.remove_from_call_log: {
- StringBuilder callIds = new StringBuilder();
- for (Uri callUri : getCallLogEntryUris()) {
- if (callIds.length() != 0) {
- callIds.append(",");
- }
- callIds.append(ContentUris.parseId(callUri));
- }
-
- getContentResolver().delete(Calls.CONTENT_URI_WITH_VOICEMAIL,
- Calls._ID + " IN (" + callIds + ")", null);
- // Also close the activity.
- finish();
- return true;
- }
-
- case R.id.edit_number_before_call:
- startActivity(
- new Intent(Intent.ACTION_DIAL, mPhoneNumberHelper.getCallUri(mNumber)));
- return true;
-
case android.R.id.home: {
onHomeSelected();
return true;
}
+ // All the options menu items are handled by onMenu... methods.
default:
throw new IllegalArgumentException();
}
}
+ public void onMenuRemoveFromCallLog(MenuItem menuItem) {
+ StringBuilder callIds = new StringBuilder();
+ for (Uri callUri : getCallLogEntryUris()) {
+ if (callIds.length() != 0) {
+ callIds.append(",");
+ }
+ callIds.append(ContentUris.parseId(callUri));
+ }
+
+ getContentResolver().delete(Calls.CONTENT_URI_WITH_VOICEMAIL,
+ Calls._ID + " IN (" + callIds + ")", null);
+ // Also close the activity.
+ finish();
+ }
+
+ public void onMenuEditNumberBeforeCall(MenuItem menuItem) {
+ startActivity(new Intent(Intent.ACTION_DIAL, mPhoneNumberHelper.getCallUri(mNumber)));
+ }
+
+ public void onMenuShareVoicemail(MenuItem menuItem) {
+ Log.w(TAG, "onMenuShareVoicemail not yet implemented");
+ }
+
+ public void onMenuTrashVoicemail(MenuItem menuItem) {
+ Log.w(TAG, "onMenuTrashVoicemail not yet implemented");
+ }
+
private void configureActionBar() {
ActionBar actionBar = getActionBar();
if (actionBar != null) {
- actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME,
- ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_TITLE
- | ActionBar.DISPLAY_SHOW_HOME);
+ actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
actionBar.setIcon(R.drawable.ic_ab_dialer_holo_dark);
}
}
diff --git a/src/com/android/contacts/PhoneCallDetailsHelper.java b/src/com/android/contacts/PhoneCallDetailsHelper.java
index f312a5d..8cdd0d0 100644
--- a/src/com/android/contacts/PhoneCallDetailsHelper.java
+++ b/src/com/android/contacts/PhoneCallDetailsHelper.java
@@ -61,10 +61,10 @@
public void setPhoneCallDetails(PhoneCallDetailsViews views, PhoneCallDetails details,
boolean useIcons, boolean isHighlighted, boolean nameOnly) {
if (useIcons) {
- views.callTypeIcons.removeAllViews();
+ views.callTypeIcons.clear();
int count = details.callTypes.length;
for (int index = 0; index < count && index < MAX_CALL_TYPE_ICONS; ++index) {
- mCallTypeHelper.inflateCallTypeIcon(details.callTypes[index], views.callTypeIcons);
+ views.callTypeIcons.add(details.callTypes[index]);
}
views.callTypeIcons.setVisibility(View.VISIBLE);
if (count > MAX_CALL_TYPE_ICONS) {
@@ -77,14 +77,13 @@
views.callTypeSeparator.setVisibility(View.GONE);
}
} else {
- String callTypeName;
// 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(
isHighlighted ? mCallTypeHelper.getHighlightedCallTypeText(callType)
: mCallTypeHelper.getCallTypeText(callType));
- views.callTypeIcons.removeAllViews();
+ views.callTypeIcons.clear();
views.callTypeText.setVisibility(View.VISIBLE);
views.callTypeSeparator.setVisibility(View.VISIBLE);
diff --git a/src/com/android/contacts/PhoneCallDetailsViews.java b/src/com/android/contacts/PhoneCallDetailsViews.java
index 19e931f..c07e337 100644
--- a/src/com/android/contacts/PhoneCallDetailsViews.java
+++ b/src/com/android/contacts/PhoneCallDetailsViews.java
@@ -16,9 +16,10 @@
package com.android.contacts;
+import com.android.contacts.calllog.CallTypeIconsView;
+
import android.content.Context;
import android.view.View;
-import android.widget.LinearLayout;
import android.widget.TextView;
/**
@@ -27,14 +28,15 @@
public final class PhoneCallDetailsViews {
public final TextView nameView;
public final View callTypeView;
- public final LinearLayout callTypeIcons;
+ public final CallTypeIconsView callTypeIcons;
public final TextView callTypeText;
public final View callTypeSeparator;
public final TextView dateView;
public final TextView numberView;
- private PhoneCallDetailsViews(TextView nameView, View callTypeView, LinearLayout callTypeIcons,
- TextView callTypeText, View callTypeSeparator, TextView dateView, TextView numberView) {
+ private PhoneCallDetailsViews(TextView nameView, View callTypeView,
+ CallTypeIconsView callTypeIcons, TextView callTypeText, View callTypeSeparator,
+ TextView dateView, TextView numberView) {
this.nameView = nameView;
this.callTypeView = callTypeView;
this.callTypeIcons = callTypeIcons;
@@ -54,7 +56,7 @@
public static PhoneCallDetailsViews fromView(View view) {
return new PhoneCallDetailsViews((TextView) view.findViewById(R.id.name),
view.findViewById(R.id.call_type),
- (LinearLayout) view.findViewById(R.id.call_type_icons),
+ (CallTypeIconsView) view.findViewById(R.id.call_type_icons),
(TextView) view.findViewById(R.id.call_type_name),
view.findViewById(R.id.call_type_separator),
(TextView) view.findViewById(R.id.date),
@@ -65,7 +67,7 @@
return new PhoneCallDetailsViews(
new TextView(context),
new View(context),
- new LinearLayout(context),
+ new CallTypeIconsView(context),
new TextView(context),
new View(context),
new TextView(context),
diff --git a/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java b/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java
index 26275af..3e3ba36 100644
--- a/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java
+++ b/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java
@@ -64,19 +64,20 @@
@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);
- }
+ final View result = convertView == null
+ ? mLayoutInflater.inflate(R.layout.call_detail_history_item, parent, false)
+ : convertView;
PhoneCallDetails details = mPhoneCallDetails[position];
- FrameLayout callTypeIconView = (FrameLayout) convertView.findViewById(R.id.call_type_icon);
- TextView callTypeTextView = (TextView) convertView.findViewById(R.id.call_type_text);
- TextView dateView = (TextView) convertView.findViewById(R.id.date);
- TextView durationView = (TextView) convertView.findViewById(R.id.duration);
+ CallTypeIconsView callTypeIconView =
+ (CallTypeIconsView) result.findViewById(R.id.call_type_icon);
+ TextView callTypeTextView = (TextView) result.findViewById(R.id.call_type_text);
+ TextView dateView = (TextView) result.findViewById(R.id.date);
+ TextView durationView = (TextView) result.findViewById(R.id.duration);
int callType = details.callTypes[0];
- callTypeIconView.removeAllViews();
- mCallTypeHelper.inflateCallTypeIcon(callType, callTypeIconView);
+ callTypeIconView.clear();
+ callTypeIconView.add(callType);
callTypeTextView.setText(mCallTypeHelper.getCallTypeText(callType));
// Set the date.
CharSequence dateValue = DateUtils.formatDateRange(mContext, details.date, details.date,
@@ -91,7 +92,7 @@
durationView.setText(formatDuration(details.duration));
}
- return convertView;
+ return result;
}
private String formatDuration(long elapsedSeconds) {
diff --git a/src/com/android/contacts/calllog/CallLogFragment.java b/src/com/android/contacts/calllog/CallLogFragment.java
index abc9adf..0999b44 100644
--- a/src/com/android/contacts/calllog/CallLogFragment.java
+++ b/src/com/android/contacts/calllog/CallLogFragment.java
@@ -313,11 +313,7 @@
mPreDrawListener = null;
Resources resources = getResources();
- LayoutInflater layoutInflater = getActivity().getLayoutInflater();
- CallTypeHelper callTypeHelper = new CallTypeHelper(resources, layoutInflater);
- Drawable callDrawable = resources.getDrawable(R.drawable.ic_dial_action_call);
- Drawable playDrawable = resources.getDrawable(
- R.drawable.ic_call_log_list_action_play);
+ CallTypeHelper callTypeHelper = new CallTypeHelper(resources);
mContactPhotoManager = ContactPhotoManager.getInstance(getActivity());
mPhoneNumberHelper = new PhoneNumberHelper(getResources(), mVoiceMailNumber);
@@ -678,7 +674,7 @@
if (section == CallLogQuery.SECTION_NEW_HEADER
|| section == CallLogQuery.SECTION_OLD_HEADER) {
views.listItemView.setVisibility(View.GONE);
- views.listHeaderView.setVisibility(View.VISIBLE);
+ views.listHeaderTextView.setVisibility(View.VISIBLE);
views.listHeaderTextView.setText(
section == CallLogQuery.SECTION_NEW_HEADER
? R.string.call_log_new_header
@@ -688,7 +684,7 @@
}
// Default case: an item in the call log.
views.listItemView.setVisibility(View.VISIBLE);
- views.listHeaderView.setVisibility(View.GONE);
+ views.listHeaderTextView.setVisibility(View.GONE);
final String number = c.getString(CallLogQuery.NUMBER);
final long date = c.getLong(CallLogQuery.DATE);
diff --git a/src/com/android/contacts/calllog/CallLogListItemViews.java b/src/com/android/contacts/calllog/CallLogListItemViews.java
index 90f78f7..368a868 100644
--- a/src/com/android/contacts/calllog/CallLogListItemViews.java
+++ b/src/com/android/contacts/calllog/CallLogListItemViews.java
@@ -45,14 +45,12 @@
public final PhoneCallDetailsViews phoneCallDetailsViews;
/** The item view for a stand-alone row, or null for other types of rows. */
public final View listItemView;
- /** The header view for a stand-alone row, or null for other types of rows. */
- public final View listHeaderView;
/** The text of the header in a stand-alone row, or null for other types of rows. */
public final TextView listHeaderTextView;
private CallLogListItemViews(QuickContactBadge quickContactView, ImageView photoView,
View callView, View playView, View unheardView, View dividerView,
- PhoneCallDetailsViews phoneCallDetailsViews, View listItemView, View listHeaderView,
+ PhoneCallDetailsViews phoneCallDetailsViews, View listItemView,
TextView listHeaderTextView) {
this.quickContactView = quickContactView;
this.plainPhotoView = photoView;
@@ -62,7 +60,6 @@
this.dividerView = dividerView;
this.phoneCallDetailsViews = phoneCallDetailsViews;
this.listItemView = listItemView;
- this.listHeaderView = listHeaderView;
this.listHeaderTextView = listHeaderTextView;
}
@@ -76,7 +73,6 @@
view.findViewById(R.id.divider),
PhoneCallDetailsViews.fromView(view),
view.findViewById(R.id.call_log_item),
- view.findViewById(R.id.call_log_header),
(TextView) view.findViewById(R.id.call_log_header_text));
}
@@ -90,7 +86,6 @@
new View(context),
PhoneCallDetailsViews.createForTest(context),
new View(context),
- new View(context),
new TextView(context));
}
}
diff --git a/src/com/android/contacts/calllog/CallTypeHelper.java b/src/com/android/contacts/calllog/CallTypeHelper.java
index 465e2bf..d27d4f9 100644
--- a/src/com/android/contacts/calllog/CallTypeHelper.java
+++ b/src/com/android/contacts/calllog/CallTypeHelper.java
@@ -25,16 +25,11 @@
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.text.style.StyleSpan;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
/**
* Helper class to perform operations related to call types.
*/
public class CallTypeHelper {
- /** Used to create the views for the call types. */
- private final LayoutInflater mLayoutInflater;
/** Name used to identify incoming calls. */
private final CharSequence mIncomingName;
/** Name used to identify outgoing calls. */
@@ -48,8 +43,7 @@
/** Name used to identify new voicemail calls. */
private final CharSequence mNewVoicemailName;
- public CallTypeHelper(Resources resources, LayoutInflater layoutInflater) {
- mLayoutInflater = layoutInflater;
+ public CallTypeHelper(Resources resources) {
// 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);
@@ -103,26 +97,6 @@
}
}
- /** Returns a new view for the icon to be used to represent a given call type. */
- public View inflateCallTypeIcon(int callType, ViewGroup root) {
- switch (callType) {
- case Calls.INCOMING_TYPE:
- return mLayoutInflater.inflate(R.layout.call_log_incoming_call_icon, root);
-
- case Calls.OUTGOING_TYPE:
- return mLayoutInflater.inflate(R.layout.call_log_outgoing_call_icon, root);
-
- case Calls.MISSED_TYPE:
- return mLayoutInflater.inflate(R.layout.call_log_missed_call_icon, root);
-
- case Calls.VOICEMAIL_TYPE:
- return mLayoutInflater.inflate(R.layout.call_log_voicemail_icon, root);
-
- default:
- throw new IllegalArgumentException("invalid call type: " + callType);
- }
- }
-
/** Creates a SpannableString for the given text which is bold and in the given color. */
private CharSequence addBoldAndColor(CharSequence text, int color) {
int flags = Spanned.SPAN_INCLUSIVE_INCLUSIVE;
diff --git a/src/com/android/contacts/calllog/CallTypeIconsView.java b/src/com/android/contacts/calllog/CallTypeIconsView.java
new file mode 100644
index 0000000..4fbe7d7
--- /dev/null
+++ b/src/com/android/contacts/calllog/CallTypeIconsView.java
@@ -0,0 +1,123 @@
+/*
+ * 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.google.common.collect.Lists;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.provider.CallLog.Calls;
+import android.util.AttributeSet;
+import android.view.View;
+
+import java.util.List;
+
+/**
+ * View that draws one or more symbols for different types of calls (missed calls, outgoing etc).
+ * The symbols are set up horizontally. As this view doesn't create subviews, it is better suited
+ * for ListView-recycling that a regular LinearLayout using ImageViews.
+ */
+public class CallTypeIconsView extends View {
+ private List<Integer> mCallTypes = Lists.newArrayListWithCapacity(3);
+ private Resources mResources;
+ private int mWidth;
+ private int mHeight;
+
+ public CallTypeIconsView(Context context) {
+ this(context, null);
+ }
+
+ public CallTypeIconsView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mResources = new Resources(context);
+ }
+
+ public void clear() {
+ mCallTypes.clear();
+ mWidth = 0;
+ mHeight = 0;
+ invalidate();
+ }
+
+ public void add(int callType) {
+ mCallTypes.add(callType);
+
+ final Drawable drawable = getCallTypeDrawable(callType);
+ mWidth += drawable.getIntrinsicWidth() + mResources.iconMargin;
+ mHeight = Math.max(mHeight, drawable.getIntrinsicHeight());
+ invalidate();
+ }
+
+ public int getCount() {
+ return mCallTypes.size();
+ }
+
+ public int getCallType(int index) {
+ return mCallTypes.get(index);
+ }
+
+ private Drawable getCallTypeDrawable(int callType) {
+ switch (callType) {
+ case Calls.INCOMING_TYPE:
+ return mResources.incoming;
+ case Calls.OUTGOING_TYPE:
+ return mResources.outgoing;
+ case Calls.MISSED_TYPE:
+ return mResources.missed;
+ case Calls.VOICEMAIL_TYPE:
+ return mResources.voicemail;
+ default:
+ throw new IllegalArgumentException("invalid call type: " + callType);
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(mWidth, mHeight);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ int left = 0;
+ for (Integer callType : mCallTypes) {
+ final Drawable drawable = getCallTypeDrawable(callType);
+ final int right = left + drawable.getIntrinsicWidth();
+ drawable.setBounds(left, 0, right, drawable.getIntrinsicHeight());
+ drawable.draw(canvas);
+ left = right + mResources.iconMargin;
+ }
+ }
+
+ private static class Resources {
+ public final Drawable incoming;
+ public final Drawable outgoing;
+ public final Drawable missed;
+ public final Drawable voicemail;
+ public final int iconMargin;
+
+ public Resources(Context context) {
+ final android.content.res.Resources r = context.getResources();
+ incoming = r.getDrawable(R.drawable.ic_call_incoming_holo_dark);
+ outgoing = r.getDrawable(R.drawable.ic_call_outgoing_holo_dark);
+ missed = r.getDrawable(R.drawable.ic_call_missed_holo_dark);
+ voicemail = r.getDrawable(R.drawable.ic_call_voicemail_holo_dark);
+ iconMargin = r.getDimensionPixelSize(R.dimen.call_log_icon_margin);
+ }
+ }
+}
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index c3b2de6..f550a0f 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -1990,7 +1990,8 @@
R.dimen.detail_item_side_margin);
mPaddingTop = resources.getDimensionPixelSize(
R.dimen.detail_item_vertical_margin);
- mWidePaddingLeft = 2 * mPaddingLeft +
+ mWidePaddingLeft = mPaddingLeft +
+ resources.getDimensionPixelSize(R.dimen.detail_item_icon_margin) +
resources.getDimensionPixelSize(R.dimen.detail_network_icon_size);
mPaddingRight = mPaddingLeft;
mPaddingBottom = mPaddingTop;
diff --git a/src/com/android/contacts/group/GroupBrowseListAdapter.java b/src/com/android/contacts/group/GroupBrowseListAdapter.java
index 630a397..1f06029 100644
--- a/src/com/android/contacts/group/GroupBrowseListAdapter.java
+++ b/src/com/android/contacts/group/GroupBrowseListAdapter.java
@@ -16,33 +16,159 @@
package com.android.contacts.group;
+import com.android.contacts.ContactPhotoManager;
import com.android.contacts.GroupListLoader;
import com.android.contacts.R;
import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
import com.android.internal.util.Objects;
+import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.AsyncTask;
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
+import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.Groups;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
+import android.widget.ImageView;
import android.widget.TextView;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
/**
* Adapter to populate the list of groups.
*/
public class GroupBrowseListAdapter extends BaseAdapter {
+ private static final int MAX_ICONS_PER_GROUP_ROW = 4;
+
+ private static final String[] PROJECTION_GROUP_MEMBERSHIP_INFO = new String[] {
+ GroupMembership._ID,
+ GroupMembership.PHOTO_ID
+ };
+ private static final int GROUP_MEMBERSHIP_COLUMN_PHOTO_ID = 1;
+
+ /**
+ * Arguments for asynchronous photo ID loading. See {@link AsyncPhotoIdLoadTask}
+ */
+ private static class AsyncPhotoIdLoadArg {
+ public final View icons;
+ public final long groupId;
+ public final Map<Long, ArrayList<Long>> groupPhotoIdMap;
+ public final ContentResolver contentResolver;
+ public final ContactPhotoManager contactPhotoManager;
+
+ public AsyncPhotoIdLoadArg(
+ View icons, long groupId, Map<Long, ArrayList<Long>> groupPhotoIdMap,
+ ContentResolver contentResolver, ContactPhotoManager contactPhotoManager) {
+ this.icons = icons;
+ this.groupId = groupId;
+ this.groupPhotoIdMap = groupPhotoIdMap;
+ this.contentResolver = contentResolver;
+ this.contactPhotoManager = contactPhotoManager;
+ }
+ }
+
+ /**
+ * Loads photo IDs associated with a group ID supplied from {@link AsyncPhotoIdLoadArg#groupId},
+ * storing them in {@link GroupBrowseListAdapter#mGroupPhotoIdMap}.
+ *
+ * This AsyncTask also remembers a View which is associated with the group ID at the moment it
+ * is initiated (we use {@link View#setTag(Object) and View#getTag() to associate them}. If the
+ * View is still associated with the group ID after the asynchronous photo ID load, this class
+ * also asks {@link ContactPhotoManager} to load actual photo contents. Its parent (typically
+ * ListView) may reuse Views for different group IDs, so the photo content load often don't
+ * occur.
+ */
+ private static class AsyncPhotoIdLoadTask extends
+ AsyncTask<AsyncPhotoIdLoadArg, Void, ArrayList<Long>> {
+
+ private View mIcons;
+ private long mGroupId;
+ private Map<Long, ArrayList<Long>> mGroupPhotoIdMap;
+ private ContentResolver mContentResolver;
+ private ContactPhotoManager mContactPhotoManager;
+
+ @Override
+ protected ArrayList<Long> doInBackground(AsyncPhotoIdLoadArg... params) {
+ final AsyncPhotoIdLoadArg arg = params[0];
+ mIcons = arg.icons;
+ mGroupId = arg.groupId;
+ mGroupPhotoIdMap = arg.groupPhotoIdMap;
+ mContentResolver = arg.contentResolver;
+ mContactPhotoManager = arg.contactPhotoManager;
+
+ // Multiple requests for one group ID is possible. We just ignore duplicates,
+ // assuming query results won't change.
+ if (mGroupPhotoIdMap.containsKey(mGroupId)) {
+ return null;
+ }
+
+ final ArrayList<Long> photoIds = new ArrayList<Long>(MAX_ICONS_PER_GROUP_ROW);
+ Cursor cursor = null;
+ try {
+ cursor = mContentResolver.query(Data.CONTENT_URI,
+ PROJECTION_GROUP_MEMBERSHIP_INFO,
+ GroupMembership.MIMETYPE + "=? AND "
+ + GroupMembership.PHOTO_ID + " IS NOT NULL AND "
+ + GroupMembership.GROUP_ROW_ID + "=?",
+ new String[] { GroupMembership.CONTENT_ITEM_TYPE,
+ String.valueOf(mGroupId) }, null);
+ if (cursor != null) {
+ int count = 0;
+ while (cursor.moveToNext() && count < MAX_ICONS_PER_GROUP_ROW) {
+ photoIds.add(cursor.getLong(GROUP_MEMBERSHIP_COLUMN_PHOTO_ID));
+ count++;
+ }
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ return photoIds;
+ }
+
+ @Override
+ protected void onPostExecute(ArrayList<Long> photoIds) {
+ if (photoIds == null) {
+ return;
+ }
+
+ mGroupPhotoIdMap.put(mGroupId, photoIds);
+
+ final View icons = mIcons;
+ // If the original group ID, which was supplied when this AsyncTask was executed, is
+ // consistent with the ID inside mArgs, it means the View isn't reused by the
+ // other groups, and thus we can assume these Views are available for the group ID.
+ final Long currentGroupId = (Long) icons.getTag();
+ if (currentGroupId == mGroupId) {
+ final ImageView[] children = getIconViewsSordedByFillOrder(icons);
+ for (int i = 0; i < children.length; i++) {
+ final long photoId = i < photoIds.size() ? photoIds.get(i) : 0;
+ mContactPhotoManager.loadPhoto(children[i], photoId);
+ }
+ }
+ }
+ }
+
private final Context mContext;
private final LayoutInflater mLayoutInflater;
private final AccountTypeManager mAccountTypeManager;
+ private final Map<Long, ArrayList<Long>> mGroupPhotoIdMap =
+ new ConcurrentHashMap<Long, ArrayList<Long>>();
+
+ private final ContactPhotoManager mContactPhotoManager;
+
private Cursor mCursor;
private boolean mSelectionVisible;
@@ -52,6 +178,7 @@
mContext = context;
mLayoutInflater = LayoutInflater.from(context);
mAccountTypeManager = AccountTypeManager.getInstance(mContext);
+ mContactPhotoManager = ContactPhotoManager.getInstance(mContext);
}
public void setCursor(Cursor cursor) {
@@ -179,6 +306,32 @@
viewCache.groupTitle.setText(entry.getTitle());
viewCache.groupMemberCount.setText(memberCountString);
+ final View icons = result.findViewById(R.id.icons);
+ final ImageView[] children = getIconViewsSordedByFillOrder(icons);
+ final ArrayList<Long> photoIds = mGroupPhotoIdMap.get(entry.getGroupId());
+
+ // Let the icon holder remember its associated group ID.
+ // Each AsyncTask loading photo IDs will compare this ID with the AsyncTask's argument, and
+ // check if the bound View is reused by the other list items or not. If the View is reused,
+ // the group ID set here will be overridden by the new owner, thus ID inconsistency happens.
+ icons.setTag(entry.getGroupId());
+ if (photoIds != null) {
+ // Cache is available. Let the photo manager load those IDs.
+ for (int i = 0; i < children.length; i++) {
+ final long photoId = i < photoIds.size() ? photoIds.get(i) : 0;
+ mContactPhotoManager.loadPhoto(children[i], photoId);
+ }
+ } else {
+ // Cache is not available. Load photo IDs asynchronously.
+ for (ImageView child : children) {
+ mContactPhotoManager.loadPhoto(child, 0);
+ }
+ new AsyncPhotoIdLoadTask().execute(
+ new AsyncPhotoIdLoadArg(icons, entry.getGroupId(),
+ mGroupPhotoIdMap, mContext.getContentResolver(),
+ mContactPhotoManager));
+ }
+
if (mSelectionVisible) {
result.setActivated(isSelectedGroup(groupUri));
}
@@ -201,6 +354,19 @@
}
/**
+ * Get ImageView objects inside the given View, sorted by the order photos should be filled.
+ */
+ private static ImageView[] getIconViewsSordedByFillOrder(View icons) {
+ final ImageView[] children = new ImageView[] {
+ (ImageView) icons.findViewById(R.id.icon_4),
+ (ImageView) icons.findViewById(R.id.icon_2),
+ (ImageView) icons.findViewById(R.id.icon_3),
+ (ImageView) icons.findViewById(R.id.icon_1)
+ };
+ return children;
+ }
+
+ /**
* Cache of the children views of a contact detail entry represented by a
* {@link GroupListItem}
*/
diff --git a/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java b/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java
index edc1bb4..d306209 100644
--- a/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java
+++ b/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java
@@ -66,7 +66,6 @@
private SeekBar mPlaybackSeek;
private ImageButton mStartStopButton;
private ImageButton mPlaybackSpeakerphone;
- private ImageButton mPlaybackTrashButton;
private TextView mPlaybackPositionText;
private ImageButton mRateDecreaseButton;
private ImageButton mRateIncreaseButton;
@@ -80,7 +79,6 @@
mPlaybackSeek = (SeekBar) view.findViewById(R.id.playback_seek);
mStartStopButton = (ImageButton) view.findViewById(R.id.playback_start_stop);
mPlaybackSpeakerphone = (ImageButton) view.findViewById(R.id.playback_speakerphone);
- mPlaybackTrashButton = (ImageButton) view.findViewById(R.id.playback_trash);
mPlaybackPositionText = (TextView) view.findViewById(R.id.playback_position_text);
mRateDecreaseButton = (ImageButton) view.findViewById(R.id.rate_decrease_button);
mRateIncreaseButton = (ImageButton) view.findViewById(R.id.rate_increase_button);
@@ -188,11 +186,6 @@
}
@Override
- public void setDeleteButtonListener(View.OnClickListener listener) {
- mPlaybackTrashButton.setOnClickListener(listener);
- }
-
- @Override
public void setPositionSeekListener(SeekBar.OnSeekBarChangeListener listener) {
mPlaybackSeek.setOnSeekBarChangeListener(listener);
}
diff --git a/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java b/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
index 0e7470a..eac502d 100644
--- a/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
+++ b/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
@@ -56,7 +56,6 @@
void setStartStopListener(View.OnClickListener listener);
void setPositionSeekListener(SeekBar.OnSeekBarChangeListener listener);
void setSpeakerphoneListener(View.OnClickListener listener);
- void setDeleteButtonListener(View.OnClickListener listener);
void setClipPosition(int clipPositionInMillis, int clipLengthInMillis);
int getDesiredClipPosition();
void playbackStarted();
@@ -138,7 +137,6 @@
mView.setPositionSeekListener(new PlaybackPositionListener());
mView.setStartStopListener(new StartStopButtonListener());
mView.setSpeakerphoneListener(new SpeakerphoneListener());
- mView.setDeleteButtonListener(new DeleteButtonListener());
mPlayer.setOnErrorListener(new MediaPlayerErrorListener());
mPlayer.setOnCompletionListener(new MediaPlayerCompletionListener());
mView.setSpeakerPhoneOn(mView.isSpeakerPhoneOn());
@@ -303,15 +301,6 @@
}
}
- private class DeleteButtonListener implements View.OnClickListener {
- @Override
- public void onClick(View v) {
- // TODO: Temporarily removed this whilst the team discuss the merits of porting
- // the VoicemailHelper class across vs just hard-coding the delete via cursor.
- mView.finish();
- }
- }
-
private class StartStopButtonListener implements View.OnClickListener {
@Override
public void onClick(View arg0) {
diff --git a/tests/src/com/android/contacts/CallDetailActivityTest.java b/tests/src/com/android/contacts/CallDetailActivityTest.java
index c1efa3f..cdb6e44 100644
--- a/tests/src/com/android/contacts/CallDetailActivityTest.java
+++ b/tests/src/com/android/contacts/CallDetailActivityTest.java
@@ -103,7 +103,7 @@
Menu menu = new ContextMenuBuilder(activity);
activity.onCreateOptionsMenu(menu);
activity.onPrepareOptionsMenu(menu);
- assertFalse(menu.findItem(R.id.remove_from_call_log).isVisible());
+ assertFalse(menu.findItem(R.id.menu_remove_from_call_log).isVisible());
}
/** Test to check that I haven't broken the remove-from-call-log entry from regular calls. */
@@ -113,7 +113,7 @@
Menu menu = new ContextMenuBuilder(activity);
activity.onCreateOptionsMenu(menu);
activity.onPrepareOptionsMenu(menu);
- assertTrue(menu.findItem(R.id.remove_from_call_log).isVisible());
+ assertTrue(menu.findItem(R.id.menu_remove_from_call_log).isVisible());
}
/**
diff --git a/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java b/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
index 8feca19..1e5d879 100644
--- a/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
+++ b/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
@@ -25,7 +25,6 @@
import android.content.res.Resources;
import android.provider.CallLog.Calls;
import android.test.AndroidTestCase;
-import android.view.LayoutInflater;
import android.view.View;
import java.util.GregorianCalendar;
@@ -59,9 +58,7 @@
super.setUp();
Context context = getContext();
Resources resources = context.getResources();
- LayoutInflater layoutInflater =
- (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- CallTypeHelper callTypeHelper = new CallTypeHelper(resources, layoutInflater);
+ CallTypeHelper callTypeHelper = new CallTypeHelper(resources);
mPhoneNumberHelper = new PhoneNumberHelper(resources, TEST_VOICEMAIL_NUMBER);
mHelper = new PhoneCallDetailsHelper(resources, callTypeHelper, mPhoneNumberHelper);
mViews = PhoneCallDetailsViews.createForTest(context);
@@ -128,25 +125,30 @@
public void testSetPhoneCallDetails_CallTypeIcons() {
setPhoneCallDetailsWithCallTypeIcons(Calls.INCOMING_TYPE);
- assertCallTypeIconsEquals(R.id.call_log_incoming_call_icon);
+ assertCallTypeIconsEquals(Calls.INCOMING_TYPE);
setPhoneCallDetailsWithCallTypeIcons(Calls.OUTGOING_TYPE);
- assertCallTypeIconsEquals(R.id.call_log_outgoing_call_icon);
+ assertCallTypeIconsEquals(Calls.OUTGOING_TYPE);
setPhoneCallDetailsWithCallTypeIcons(Calls.MISSED_TYPE);
- assertCallTypeIconsEquals(R.id.call_log_missed_call_icon);
+ assertCallTypeIconsEquals(Calls.MISSED_TYPE);
setPhoneCallDetailsWithCallTypeIcons(Calls.VOICEMAIL_TYPE);
- assertCallTypeIconsEquals(R.id.call_log_voicemail_icon);
+ assertCallTypeIconsEquals(Calls.VOICEMAIL_TYPE);
}
public void testSetPhoneCallDetails_MultipleCallTypeIcons() {
setPhoneCallDetailsWithCallTypeIcons(Calls.INCOMING_TYPE, Calls.OUTGOING_TYPE);
- assertCallTypeIconsEquals(R.id.call_log_incoming_call_icon,
- R.id.call_log_outgoing_call_icon);
+ assertCallTypeIconsEquals(Calls.INCOMING_TYPE, Calls.OUTGOING_TYPE);
setPhoneCallDetailsWithCallTypeIcons(Calls.MISSED_TYPE, Calls.MISSED_TYPE);
- assertCallTypeIconsEquals(R.id.call_log_missed_call_icon, R.id.call_log_missed_call_icon);
+ assertCallTypeIconsEquals(Calls.MISSED_TYPE, Calls.MISSED_TYPE);
+ }
+
+ public void testSetPhoneCallDetails_MultipleCallTypeIconsLastOneDropped() {
+ setPhoneCallDetailsWithCallTypeIcons(Calls.MISSED_TYPE, Calls.MISSED_TYPE,
+ Calls.INCOMING_TYPE, Calls.OUTGOING_TYPE);
+ assertCallTypeIconsEquals(Calls.MISSED_TYPE, Calls.MISSED_TYPE, Calls.INCOMING_TYPE);
}
public void testSetPhoneCallDetails_CallTypeText() {
@@ -222,10 +224,10 @@
/** Asserts that the call type contains the images with the given drawables. */
private void assertCallTypeIconsEquals(int... ids) {
- assertEquals(ids.length, mViews.callTypeIcons.getChildCount());
+ assertEquals(ids.length, mViews.callTypeIcons.getCount());
for (int index = 0; index < ids.length; ++index) {
int id = ids[index];
- assertEquals(id, mViews.callTypeIcons.getChildAt(index).getId());
+ assertEquals(id, mViews.callTypeIcons.getCallType(index));
}
assertEquals(View.VISIBLE, mViews.callTypeIcons.getVisibility());
assertEquals(View.GONE, mViews.callTypeText.getVisibility());
diff --git a/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java b/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
index 79ebf4d..4628b8e 100644
--- a/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
+++ b/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
@@ -24,7 +24,6 @@
import android.content.res.Resources;
import android.provider.CallLog.Calls;
import android.test.AndroidTestCase;
-import android.view.LayoutInflater;
import android.view.View;
/**
@@ -56,9 +55,7 @@
super.setUp();
Context context = getContext();
Resources resources = context.getResources();
- LayoutInflater layoutInflater =
- (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- CallTypeHelper callTypeHelper = new CallTypeHelper(resources, layoutInflater);
+ CallTypeHelper callTypeHelper = new CallTypeHelper(resources);
mPhoneNumberHelper = new PhoneNumberHelper(resources, TEST_VOICEMAIL_NUMBER);
PhoneCallDetailsHelper phoneCallDetailsHelper = new PhoneCallDetailsHelper(
resources, callTypeHelper, mPhoneNumberHelper);