Merge "Create the voicemail fragment on-demand, not every time."
diff --git a/res/drawable-hdpi/ab_bottom_opaque_dark_holo.9.png b/res/drawable-hdpi/ab_bottom_opaque_dark_holo.9.png
new file mode 100644
index 0000000..4991dff
--- /dev/null
+++ b/res/drawable-hdpi/ab_bottom_opaque_dark_holo.9.png
Binary files differ
diff --git a/res/drawable-hdpi/ab_stacked_opaque_dark_holo.9.png b/res/drawable-hdpi/ab_stacked_opaque_dark_holo.9.png
new file mode 100644
index 0000000..23320ea
--- /dev/null
+++ b/res/drawable-hdpi/ab_stacked_opaque_dark_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/ab_bottom_opaque_dark_holo.9.png b/res/drawable-mdpi/ab_bottom_opaque_dark_holo.9.png
new file mode 100644
index 0000000..15bef5d
--- /dev/null
+++ b/res/drawable-mdpi/ab_bottom_opaque_dark_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/ab_stacked_opaque_dark_holo.9.png b/res/drawable-mdpi/ab_stacked_opaque_dark_holo.9.png
new file mode 100644
index 0000000..3e912f5
--- /dev/null
+++ b/res/drawable-mdpi/ab_stacked_opaque_dark_holo.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/ab_bottom_opaque_dark_holo.9.png b/res/drawable-xhdpi/ab_bottom_opaque_dark_holo.9.png
new file mode 100644
index 0000000..454e8b4
--- /dev/null
+++ b/res/drawable-xhdpi/ab_bottom_opaque_dark_holo.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/ab_stacked_opaque_dark_holo.9.png b/res/drawable-xhdpi/ab_stacked_opaque_dark_holo.9.png
new file mode 100644
index 0000000..71e4c23
--- /dev/null
+++ b/res/drawable-xhdpi/ab_stacked_opaque_dark_holo.9.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 22f0412..4cb4096 100644
--- a/res/layout-sw580dp-w1000dp/contact_detail_list_item.xml
+++ b/res/layout-sw580dp-w1000dp/contact_detail_list_item.xml
@@ -17,120 +17,115 @@
*/
-->
+<!-- Note: padding might be controlled programatically -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:minHeight="@dimen/detail_min_line_item_height">
- <LinearLayout
- android:layout_width="match_parent"
+ <!-- Note: padding might be controlled programatically -->
+ <com.android.contacts.detail.PrimaryActionViewContainer
+ android:id="@+id/primary_action_view_container"
+ android:layout_width="0dip"
+ android:layout_weight="1"
android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:orientation="vertical"
- android:minHeight="@dimen/detail_min_line_item_height">
+ android:orientation="horizontal"
+ android:layout_gravity="center_vertical"
+ android:focusable="true"
+ android:background="?android:attr/selectableItemBackground">
<LinearLayout
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_gravity="center_vertical">
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:paddingLeft="12dip"
+ android:orientation="vertical">
- <FrameLayout
- android:layout_width="@dimen/detail_item_type_width"
- android:layout_height="@dimen/detail_min_line_item_height"
- android:paddingLeft="@dimen/detail_item_side_margin">
+ <TextView
+ android:id="@+id/data"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
- <TextView
- android:id="@+id/kind"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="gone" />
+ <TextView
+ android:id="@+id/footer"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:visibility="gone" />
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:orientation="horizontal">
+ </LinearLayout>
- <TextView
- android:id="@+id/type"
- style="@style/ContactDetailItemType" />
+ <ImageView
+ android:id="@+id/presence_icon"
+ android:layout_width="32dip"
+ android:layout_height="@dimen/detail_min_line_item_height"
+ android:layout_marginLeft="5dip"
+ android:gravity="center"
+ android:scaleType="centerInside" />
- <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" />
+ <FrameLayout
+ 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">
- </LinearLayout>
-
- </FrameLayout>
+ <TextView
+ android:id="@+id/kind"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone" />
<LinearLayout
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_weight="1"
- android:paddingLeft="12dip"
- android:orientation="vertical">
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
<TextView
- android:id="@+id/data"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium" />
+ android:id="@+id/type"
+ style="@style/ContactDetailItemType" />
- <TextView
- android:id="@+id/footer"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:visibility="gone" />
+ <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>
- <ImageView
- android:id="@+id/presence_icon"
- android:layout_width="32dip"
- android:layout_height="@dimen/detail_min_line_item_height"
- android:layout_marginLeft="5dip"
- android:gravity="center"
- android:scaleType="centerInside" />
+ <View
+ android:id="@+id/vertical_divider"
+ android:layout_width="1px"
+ android:layout_height="match_parent"
+ android:layout_marginTop="@dimen/detail_vertical_divider_vertical_margin"
+ android:layout_marginBottom="@dimen/detail_vertical_divider_vertical_margin"
+ android:background="?android:attr/dividerVertical" />
- <View
- android:id="@+id/vertical_divider"
- android:layout_width="1px"
- android:layout_height="match_parent"
- android:layout_marginTop="5dip"
- android:layout_marginBottom="5dip"
- android:layout_marginLeft="14dip"
- android:layout_marginRight="14dip"
- android:background="?android:attr/dividerVertical" />
-
- <FrameLayout
- android:id="@+id/secondary_action_button_container"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginTop="10dip"
- android:paddingLeft="@dimen/detail_item_icon_margin"
- android:paddingRight="@dimen/detail_item_icon_margin"
- android:duplicateParentState="false"
- android:background="?android:attr/selectableItemBackground">
-
- <ImageView
- android:id="@+id/secondary_action_button"
- android:layout_width="32dip"
- android:layout_height="match_parent"
- android:layout_centerVertical="true"
- android:gravity="center"
- android:scaleType="center"
- android:duplicateParentState="false" />
-
- </FrameLayout>
- </LinearLayout>
-
- </LinearLayout>
-
+ <!-- Note: padding might be controlled programatically -->
+ <FrameLayout
+ android:id="@+id/secondary_action_view_container"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingLeft="@dimen/detail_item_icon_margin"
+ android:paddingRight="@dimen/detail_item_icon_margin"
+ android:duplicateParentState="false"
+ android:focusable="true"
+ android:background="?android:attr/selectableItemBackground">
+ <ImageView
+ android:id="@+id/secondary_action_button"
+ android:layout_width="32dip"
+ android:layout_height="match_parent"
+ android:layout_centerVertical="true"
+ android:gravity="center"
+ android:scaleType="center"
+ android:duplicateParentState="false" />
+ </FrameLayout>
</LinearLayout>
diff --git a/res/layout-sw580dp-w1000dp/contact_detail_updates_fragment.xml b/res/layout-sw580dp-w1000dp/contact_detail_updates_fragment.xml
new file mode 100644
index 0000000..9b63ccf
--- /dev/null
+++ b/res/layout-sw580dp-w1000dp/contact_detail_updates_fragment.xml
@@ -0,0 +1,64 @@
+<?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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
+ android:id="@+id/contact_detail_updates_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/background_social_updates">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/detail_update_section_top_padding">
+
+ <include
+ android:id="@+id/title"
+ layout="@layout/contact_detail_kind_title_entry_view" />
+
+ <LinearLayout
+ android:id="@+id/update_list"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/detail_update_section_side_padding"
+ android:paddingRight="@dimen/detail_update_section_side_padding" />
+ </LinearLayout>
+
+ </ScrollView>
+
+ <View
+ android:id="@+id/alpha_overlay"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/black"
+ android:alpha=".50"
+ android:visibility="gone"/>
+
+ <View
+ android:id="@+id/touch_intercept_overlay"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/transparent"
+ android:visibility="gone"/>
+
+</FrameLayout>
diff --git a/res/layout-sw580dp/contact_detail_updates_fragment.xml b/res/layout-sw580dp/contact_detail_updates_fragment.xml
new file mode 100644
index 0000000..8677737
--- /dev/null
+++ b/res/layout-sw580dp/contact_detail_updates_fragment.xml
@@ -0,0 +1,79 @@
+<?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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
+ android:id="@+id/contact_detail_updates_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/background_social_updates">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/detail_update_section_top_padding">
+
+ <!-- Add a first item that gives us enough space to show the carousel -->
+ <view
+ class="com.android.contacts.widget.ProportionalLayout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ ex:ratio="0.5"
+ ex:direction="widthToHeight">
+
+ <!-- Put a dummy view here because the ProportionalLayout requires one -->
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ </view>
+
+ <include
+ android:id="@+id/title"
+ layout="@layout/contact_detail_kind_title_entry_view" />
+
+ <LinearLayout
+ android:id="@+id/update_list"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/detail_update_section_side_padding"
+ android:paddingRight="@dimen/detail_update_section_side_padding" />
+ </LinearLayout>
+
+ </ScrollView>
+
+ <View
+ android:id="@+id/alpha_overlay"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/black"
+ android:alpha=".50"
+ android:visibility="gone"/>
+
+ <View
+ android:id="@+id/touch_intercept_overlay"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/transparent"
+ android:visibility="gone"/>
+
+</FrameLayout>
diff --git a/res/layout-sw580dp/detail_header_contact_with_updates.xml b/res/layout-sw580dp/detail_header_contact_with_updates.xml
index e909434..01e4c7e 100644
--- a/res/layout-sw580dp/detail_header_contact_with_updates.xml
+++ b/res/layout-sw580dp/detail_header_contact_with_updates.xml
@@ -22,12 +22,27 @@
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:paddingTop="@dimen/detail_tab_carousel_height"
android:layout_marginTop="20dip">
+ <!-- Add a first item that gives us enough space to show the carousel -->
+ <view
+ class="com.android.contacts.widget.ProportionalLayout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ ex:ratio="0.5"
+ ex:direction="widthToHeight">
+
+ <!-- Put a dummy view here because the ProportionalLayout requires one -->
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ </view>
+
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
diff --git a/res/layout-sw580dp/quickcontact_activity.xml b/res/layout-sw580dp/quickcontact_activity.xml
index 6b381a9..21b5ad2 100644
--- a/res/layout-sw580dp/quickcontact_activity.xml
+++ b/res/layout-sw580dp/quickcontact_activity.xml
@@ -27,7 +27,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
- <include layout="@layout/quickcontact_photo_container" />
+ <FrameLayout
+ android:layout_width="400dip"
+ android:layout_height="200dip">
+ <include layout="@layout/quickcontact_photo_container" />
+ </FrameLayout>
<View
android:id="@+id/line_before_track"
android:layout_width="match_parent"
diff --git a/res/layout-w470dp/contact_detail_fragment.xml b/res/layout-w470dp/contact_detail_fragment.xml
index 17cbc2d..5a48583 100644
--- a/res/layout-w470dp/contact_detail_fragment.xml
+++ b/res/layout-w470dp/contact_detail_fragment.xml
@@ -14,17 +14,28 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/contact_detail"
- android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
+ <!-- "QuickFix"- button (Copy to local contact, add to group) -->
+ <Button
+ android:id="@+id/contact_quick_fix"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentBottom="true"
+ android:layout_marginRight="40dip"
+ android:layout_marginTop="20dip"
+ android:layout_marginBottom="20dip" />
+
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
- android:layout_height="0px"
- android:layout_weight="1" >
+ android:layout_above="@id/contact_quick_fix"
+ android:layout_height="match_parent" >
<ImageView android:id="@+id/photo"
android:scaleType="centerCrop"
@@ -41,12 +52,11 @@
android:layout_weight="1"
android:divider="@null"/>
- </LinearLayout>
+ </LinearLayout>
<ScrollView android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="0px"
- android:layout_weight="1"
android:visibility="gone">
<TextView android:id="@+id/emptyText"
android:layout_width="match_parent"
@@ -60,17 +70,6 @@
android:lineSpacingMultiplier="0.92"/>
</ScrollView>
- <!-- "QuickFix"- button (Copy to local contact, add to group) -->
- <Button
- android:id="@+id/contact_quick_fix"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="gone"
- android:layout_gravity="right"
- android:layout_marginRight="40dip"
- android:layout_marginTop="20dip"
- android:layout_marginBottom="20dip" />
-
<View
android:id="@+id/alpha_overlay"
android:layout_width="match_parent"
@@ -89,5 +88,5 @@
android:layout_alignParentTop="true"
android:background="@android:color/transparent"
android:visibility="gone"/>
-</LinearLayout>
+</RelativeLayout>
diff --git a/res/layout-w470dp/contact_detail_updates_fragment.xml b/res/layout-w470dp/contact_detail_updates_fragment.xml
new file mode 100644
index 0000000..9b63ccf
--- /dev/null
+++ b/res/layout-w470dp/contact_detail_updates_fragment.xml
@@ -0,0 +1,64 @@
+<?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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
+ android:id="@+id/contact_detail_updates_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/background_social_updates">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/detail_update_section_top_padding">
+
+ <include
+ android:id="@+id/title"
+ layout="@layout/contact_detail_kind_title_entry_view" />
+
+ <LinearLayout
+ android:id="@+id/update_list"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/detail_update_section_side_padding"
+ android:paddingRight="@dimen/detail_update_section_side_padding" />
+ </LinearLayout>
+
+ </ScrollView>
+
+ <View
+ android:id="@+id/alpha_overlay"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/black"
+ android:alpha=".50"
+ android:visibility="gone"/>
+
+ <View
+ android:id="@+id/touch_intercept_overlay"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/transparent"
+ android:visibility="gone"/>
+
+</FrameLayout>
diff --git a/res/layout-w470dp/quickcontact_activity.xml b/res/layout-w470dp/quickcontact_activity.xml
index df68761..36d499d 100644
--- a/res/layout-w470dp/quickcontact_activity.xml
+++ b/res/layout-w470dp/quickcontact_activity.xml
@@ -15,6 +15,7 @@
-->
<view
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
class="com.android.contacts.quickcontact.FloatingChildLayout"
android:id="@+id/floating_layout"
android:layout_width="match_parent"
@@ -25,13 +26,20 @@
<LinearLayout
android:id="@android:id/content"
android:layout_width="match_parent"
- android:layout_height="@dimen/quick_contact_picture_height"
+ android:layout_height="match_parent"
android:padding="32dip"
android:orientation="horizontal">
- <include layout="@layout/quickcontact_photo_container" />
+ <view
+ class="com.android.contacts.widget.ProportionalLayout"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ ex:ratio="1.0"
+ ex:direction="heightToWidth">
+ <include layout="@layout/quickcontact_photo_container" />
+ </view>
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="@dimen/quick_contact_picture_height"
+ android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/quickcontact_track" />
<android.support.v4.view.ViewPager
diff --git a/res/layout/call_detail.xml b/res/layout/call_detail.xml
index 6e1f4fd..94bc072 100644
--- a/res/layout/call_detail.xml
+++ b/res/layout/call_detail.xml
@@ -15,6 +15,7 @@
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
@@ -31,21 +32,30 @@
<include layout="@layout/call_log_voicemail_status"/>
</FrameLayout>
- <ImageView
- android:id="@+id/contact_background"
+ <view
+ class="com.android.contacts.widget.ProportionalLayout"
+ android:id="@+id/contact_background_sizer"
android:layout_width="match_parent"
- android:layout_height="@dimen/call_detail_contact_background_height"
+ android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@id/voicemail_status"
- android:adjustViewBounds="true"
- android:scaleType="centerCrop"
- android:background="@drawable/ic_contact_picture"
- />
+ ex:ratio="0.5"
+ ex:direction="widthToHeight"
+ >
+ <ImageView
+ android:id="@+id/contact_background"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:adjustViewBounds="true"
+ android:scaleType="centerCrop"
+ android:background="@drawable/ic_contact_picture"
+ />
+ </view>
<LinearLayout
android:id="@+id/voicemail_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@id/contact_background"
+ android:layout_below="@id/contact_background_sizer"
>
<!-- The voicemail fragment will be put here. -->
</LinearLayout>
@@ -54,14 +64,14 @@
android:layout_height="@dimen/call_detail_contact_background_overlay_height"
android:background="#3F000000"
android:layout_alignParentLeft="true"
- android:layout_alignBottom="@id/contact_background"
+ android:layout_alignBottom="@id/contact_background_sizer"
/>
<RelativeLayout
android:id="@+id/contact_text"
android:layout_width="match_parent"
android:layout_height="@dimen/call_detail_contact_background_overlay_height"
android:layout_alignParentLeft="true"
- android:layout_alignBottom="@id/contact_background"
+ android:layout_alignBottom="@id/contact_background_sizer"
android:paddingLeft="@dimen/call_detail_contact_name_margin"
>
<ImageView
diff --git a/res/layout/contact_detail_list_item.xml b/res/layout/contact_detail_list_item.xml
index e96b7f0..205bc81 100644
--- a/res/layout/contact_detail_list_item.xml
+++ b/res/layout/contact_detail_list_item.xml
@@ -17,86 +17,100 @@
*/
-->
+<!-- Note: padding might be controlled programatically -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:gravity="center_vertical">
+ android:gravity="center_vertical"
+ android:minHeight="@dimen/detail_min_line_item_height">
- <LinearLayout
+ <!-- Note: padding might be controlled programatically -->
+ <com.android.contacts.detail.PrimaryActionViewContainer
+ android:id="@+id/primary_action_view_container"
android:layout_width="0dip"
- android:layout_height="wrap_content"
android:layout_weight="1"
- android:orientation="vertical"
- android:paddingLeft="8dip"
- android:gravity="center_vertical">
-
- <TextView
- android:id="@+id/kind"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="gone" />
-
- <TextView
- android:id="@+id/data"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:textAppearance="?android:attr/textAppearanceMedium" />
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:focusable="true"
+ android:background="?android:attr/selectableItemBackground">
<LinearLayout
- android:layout_width="wrap_content"
+ android:layout_width="0dip"
android:layout_height="wrap_content"
- android:orientation="horizontal">
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:paddingLeft="8dip"
+ android:gravity="center_vertical">
<TextView
- android:id="@+id/type"
- style="@style/ContactDetailItemType" />
+ android:id="@+id/kind"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone" />
- <View
- android:id="@+id/primary_indicator"
- android:layout_width="16dip"
- android:layout_height="16dip"
- android:visibility="gone"
+ <TextView
+ android:id="@+id/data"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:background="@drawable/ic_menu_mark" />
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <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>
+
+ <TextView
+ android:id="@+id/footer"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:visibility="gone" />
</LinearLayout>
- <TextView
- android:id="@+id/footer"
- android:layout_width="wrap_content"
+ <ImageView
+ android:id="@+id/presence_icon"
+ android:layout_width="32dip"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:visibility="gone" />
-
- </LinearLayout>
-
- <ImageView
- android:id="@+id/presence_icon"
- android:layout_width="32dip"
- android:layout_height="wrap_content"
- android:layout_marginLeft="5dip"
- android:gravity="center"
- android:scaleType="centerInside" />
+ android:layout_marginLeft="5dip"
+ android:gravity="center"
+ android:scaleType="centerInside" />
+ </com.android.contacts.detail.PrimaryActionViewContainer>
<View
android:id="@+id/vertical_divider"
android:layout_width="1dip"
android:layout_height="match_parent"
- android:layout_marginTop="4dip"
- android:layout_marginBottom="4dip"
+ android:layout_marginTop="@dimen/detail_vertical_divider_vertical_margin"
+ android:layout_marginBottom="@dimen/detail_vertical_divider_vertical_margin"
android:background="?android:attr/dividerVertical" />
+ <!-- Note: padding might be controlled programatically -->
<FrameLayout
- android:id="@+id/secondary_action_button_container"
+ android:id="@+id/secondary_action_view_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="@dimen/detail_item_icon_margin"
android:paddingRight="@dimen/detail_item_icon_margin"
- android:duplicateParentState="false"
+ android:focusable="true"
android:background="?android:attr/selectableItemBackground">
<ImageView
android:id="@+id/secondary_action_button"
diff --git a/res/layout/contact_detail_tab_carousel.xml b/res/layout/contact_detail_tab_carousel.xml
index 175194c..fe167d1 100644
--- a/res/layout/contact_detail_tab_carousel.xml
+++ b/res/layout/contact_detail_tab_carousel.xml
@@ -18,14 +18,14 @@
xmlns:android="http://schemas.android.com/apk/res/android"
class="com.android.contacts.detail.ContactDetailTabCarousel"
android:layout_width="match_parent"
- android:layout_height="@dimen/detail_tab_carousel_height"
+ android:layout_height="wrap_content"
android:scrollbars="none"
android:fadingEdge="none">
<LinearLayout
android:id="@+id/tab_container"
android:layout_width="match_parent"
- android:layout_height="@dimen/detail_tab_carousel_height"
+ android:layout_height="match_parent"
android:orientation="horizontal">
<include
@@ -38,4 +38,4 @@
</LinearLayout>
-</view>
\ No newline at end of file
+</view>
diff --git a/res/layout/contact_detail_updates_fragment.xml b/res/layout/contact_detail_updates_fragment.xml
index 92f3575..95eb0a5 100644
--- a/res/layout/contact_detail_updates_fragment.xml
+++ b/res/layout/contact_detail_updates_fragment.xml
@@ -15,6 +15,7 @@
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
android:id="@+id/contact_detail_updates_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -22,7 +23,6 @@
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingTop="@dimen/detail_tab_carousel_height"
android:background="@color/background_social_updates">
<LinearLayout
@@ -31,6 +31,21 @@
android:layout_height="wrap_content"
android:paddingTop="@dimen/detail_update_section_top_padding">
+ <!-- Add a first item that gives us enough space to show the carousel -->
+ <view
+ class="com.android.contacts.widget.ProportionalLayout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ ex:ratio="0.5"
+ ex:direction="widthToHeight">
+
+ <!-- Put a dummy view here because the ProportionalLayout requires one -->
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ </view>
+
<include
android:id="@+id/title"
layout="@layout/contact_detail_kind_title_entry_view" />
@@ -39,10 +54,9 @@
android:id="@+id/update_list"
android:orientation="vertical"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingLeft="@dimen/detail_update_section_side_padding"
- android:paddingRight="@dimen/detail_update_section_side_padding" />
+ android:layout_height="wrap_content" />
</LinearLayout>
+
</ScrollView>
<View
@@ -59,5 +73,5 @@
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:visibility="gone"/>
-</FrameLayout>
+</FrameLayout>
diff --git a/res/layout/contact_tile_starred.xml b/res/layout/contact_tile_starred.xml
index ba1dff2..d667a34 100644
--- a/res/layout/contact_tile_starred.xml
+++ b/res/layout/contact_tile_starred.xml
@@ -61,6 +61,12 @@
android:layout_marginLeft="4dip"
style="@style/ContactTileStatusText" />
+ <ImageButton
+ android:id="@+id/contact_tile_push_state"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="?android:attr/selectableItemBackground" />
+
</RelativeLayout>
</view>
diff --git a/res/layout/contact_tile_starred_secondary_target.xml b/res/layout/contact_tile_starred_secondary_target.xml
index f7b8673..4b2639b 100644
--- a/res/layout/contact_tile_starred_secondary_target.xml
+++ b/res/layout/contact_tile_starred_secondary_target.xml
@@ -47,8 +47,15 @@
stlye="@style/ContactTileStarredName" />
<ImageButton
+ android:id="@+id/contact_tile_push_state"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="?android:attr/selectableItemBackground" />
+
+ <ImageButton
android:id="@+id/contact_tile_secondary_button"
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_alignParentBottom="true"
diff --git a/res/layout/detail_header_contact_with_updates.xml b/res/layout/detail_header_contact_with_updates.xml
index 00d1b76..8d18963 100644
--- a/res/layout/detail_header_contact_with_updates.xml
+++ b/res/layout/detail_header_contact_with_updates.xml
@@ -19,7 +19,15 @@
entry maintains vertical padding to ensure that the first contact detail is visible (and below
the tab carousel). No information has to be displayed in this header.
-->
-<FrameLayout
+<view
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
+ class="com.android.contacts.widget.ProportionalLayout"
android:layout_width="match_parent"
- android:layout_height="@dimen/detail_tab_carousel_height"/>
\ No newline at end of file
+ android:layout_height="wrap_content"
+ ex:ratio="0.5"
+ ex:direction="widthToHeight">
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+</view>
\ No newline at end of file
diff --git a/res/layout/detail_header_contact_without_updates.xml b/res/layout/detail_header_contact_without_updates.xml
index a5d4687..2de7711 100644
--- a/res/layout/detail_header_contact_without_updates.xml
+++ b/res/layout/detail_header_contact_without_updates.xml
@@ -18,15 +18,17 @@
This is a header entry in the contact details list for when the contact does not have social
updates, which means that the contact's photo will scroll with the list of details.
-->
-<FrameLayout
+<view
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
+ class="com.android.contacts.widget.ProportionalLayout"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
+ android:layout_height="wrap_content"
+ ex:ratio="0.5"
+ ex:direction="widthToHeight">
<ImageView
android:id="@+id/photo"
android:scaleType="centerCrop"
android:layout_width="match_parent"
- android:layout_height="@dimen/detail_tab_carousel_height" />
-
-</FrameLayout>
\ No newline at end of file
+ android:layout_height="match_parent" />
+</view>
\ No newline at end of file
diff --git a/res/layout/quickcontact_activity.xml b/res/layout/quickcontact_activity.xml
index 7aa2aa4..2f5a357 100644
--- a/res/layout/quickcontact_activity.xml
+++ b/res/layout/quickcontact_activity.xml
@@ -15,6 +15,7 @@
-->
<view
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
class="com.android.contacts.quickcontact.FloatingChildLayout"
android:id="@+id/floating_layout"
android:layout_width="match_parent"
@@ -29,7 +30,14 @@
android:paddingLeft="15dip"
android:paddingRight="15dip"
android:orientation="vertical">
- <include layout="@layout/quickcontact_photo_container" />
+ <view
+ class="com.android.contacts.widget.ProportionalLayout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ ex:ratio="0.5"
+ ex:direction="widthToHeight">
+ <include layout="@layout/quickcontact_photo_container" />
+ </view>
<View
android:id="@+id/line_before_track"
android:layout_width="match_parent"
diff --git a/res/layout/quickcontact_list_item.xml b/res/layout/quickcontact_list_item.xml
index f77ed3f..4ffa091 100755
--- a/res/layout/quickcontact_list_item.xml
+++ b/res/layout/quickcontact_list_item.xml
@@ -20,16 +20,18 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@drawable/quickcontact_list_item_background"
- android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical">
<LinearLayout
+ android:id="@+id/primary_action_view_container"
android:layout_width="0dip"
android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
android:layout_weight="1"
android:orientation="vertical"
android:paddingLeft="16dip"
android:paddingRight="16dip"
- android:gravity="center_vertical">
+ android:gravity="center_vertical"
+ android:background="?android:attr/selectableItemBackground">
<TextView
android:id="@android:id/text1"
android:layout_width="wrap_content"
@@ -41,6 +43,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
+ android:textAllCaps="true"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
<View
diff --git a/res/layout/quickcontact_photo_container.xml b/res/layout/quickcontact_photo_container.xml
index 3e0c935..b18fddc 100644
--- a/res/layout/quickcontact_photo_container.xml
+++ b/res/layout/quickcontact_photo_container.xml
@@ -17,13 +17,13 @@
xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout
android:id="@+id/photo_container"
- android:layout_width="@dimen/quick_contact_picture_width"
- android:layout_height="@dimen/quick_contact_picture_height"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:gravity="center_vertical">
<ImageView
android:id="@+id/photo"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:scaleType="centerCrop" />
<View
android:id="@+id/photo_text_bar"
@@ -68,7 +68,7 @@
android:layout_marginTop="-3dip" />
<TextView
android:id="@+id/timestamp"
- android:layout_width="fill_parent"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end"
diff --git a/res/layout/stream_item_one_column.xml b/res/layout/stream_item_one_column.xml
index 014e3f1..ecab57c 100644
--- a/res/layout/stream_item_one_column.xml
+++ b/res/layout/stream_item_one_column.xml
@@ -17,20 +17,24 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="@dimen/detail_update_section_item_vertical_padding"
android:orientation="vertical">
<LinearLayout
android:id="@+id/stream_item_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:paddingTop="@dimen/detail_update_section_item_vertical_padding"
android:paddingBottom="@dimen/detail_update_section_item_vertical_padding"
- android:paddingLeft="@dimen/detail_update_section_item_left_padding"
+ android:paddingLeft="@dimen/detail_update_section_item_horizontal_padding"
+ android:paddingRight="@dimen/detail_update_section_item_horizontal_padding"
+ android:background="@drawable/list_selector"
android:orientation="vertical" />
<View
android:id="@+id/horizontal_divider"
android:layout_width="match_parent"
android:layout_height="1px"
+ android:layout_marginLeft="@dimen/detail_update_section_side_padding"
+ android:layout_marginRight="@dimen/detail_update_section_side_padding"
android:background="?android:attr/dividerHorizontal" />
</LinearLayout>
diff --git a/res/layout/stream_item_text.xml b/res/layout/stream_item_text.xml
index 601dfb9..861d91f 100644
--- a/res/layout/stream_item_text.xml
+++ b/res/layout/stream_item_text.xml
@@ -25,9 +25,22 @@
android:textSize="16sp"
android:textColor="@color/social_update_text_color" />
- <TextView android:id="@+id/stream_item_attribution"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/social_update_attribution_color"/>
-</LinearLayout>
\ No newline at end of file
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView android:id="@+id/stream_item_attribution"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="@color/social_update_attribution_color" />
+
+ <TextView android:id="@+id/stream_item_comments"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="4dip"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="@color/social_update_comments_color" />
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/res/values-sw580dp-w1000dp/dimens.xml b/res/values-sw580dp-w1000dp/dimens.xml
index 7ff9026..d8503d9 100644
--- a/res/values-sw580dp-w1000dp/dimens.xml
+++ b/res/values-sw580dp-w1000dp/dimens.xml
@@ -20,7 +20,6 @@
<dimen name="action_bar_search_spacing">32dip</dimen>
<dimen name="detail_header_view_margin">16dip</dimen>
<dimen name="detail_header_attribution_height">56dip</dimen>
- <dimen name="detail_tab_carousel_height">0dip</dimen>
<dimen name="detail_update_section_top_padding">48dip</dimen>
<dimen name="contact_browser_list_left_margin">0dip</dimen>
<dimen name="contacts_count_right_margin">24dip</dimen>
diff --git a/res/values-sw580dp/dimens.xml b/res/values-sw580dp/dimens.xml
index 60da57a..4de6bb7 100644
--- a/res/values-sw580dp/dimens.xml
+++ b/res/values-sw580dp/dimens.xml
@@ -31,12 +31,10 @@
<dimen name="shortcut_icon_size">64dip</dimen>
<dimen name="list_section_height">37dip</dimen>
<dimen name="directory_header_height">56dip</dimen>
- <dimen name="detail_tab_carousel_height">256dip</dimen>
<dimen name="detail_update_section_item_vertical_padding">32dip</dimen>
<dimen name="search_view_width">400dip</dimen>
<dimen name="contact_browser_list_left_margin">0dip</dimen>
<dimen name="contacts_count_right_margin">24dip</dimen>
+ <!-- Center vertically -->
<dimen name="quick_contact_top_position">-1px</dimen>
- <dimen name="quick_contact_picture_width">400dip</dimen>
- <dimen name="quick_contact_picture_height">200dip</dimen>
</resources>
diff --git a/res/values-w470dp/dimens.xml b/res/values-w470dp/dimens.xml
index c77d8c2..7da25d7 100644
--- a/res/values-w470dp/dimens.xml
+++ b/res/values-w470dp/dimens.xml
@@ -14,8 +14,6 @@
limitations under the License.
-->
<resources>
- <dimen name="detail_tab_carousel_height">0dip</dimen>
+ <!-- Center vertically -->
<dimen name="quick_contact_top_position">-1px</dimen>
- <dimen name="quick_contact_picture_width">174dip</dimen>
- <dimen name="quick_contact_picture_height">-1px</dimen>
</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 0b263a4..2ca8512 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -4,9 +4,9 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
-
+
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -36,4 +36,87 @@
</attr>
</declare-styleable>
+ <declare-styleable name="InterpolatingLayout_Layout">
+ <attr name="layout_narrowParentWidth" format="dimension"/>
+ <attr name="layout_narrowWidth" format="dimension"/>
+ <attr name="layout_narrowMarginLeft" format="dimension"/>
+ <attr name="layout_narrowMarginRight" format="dimension"/>
+ <attr name="layout_narrowPaddingLeft" format="dimension"/>
+ <attr name="layout_narrowPaddingRight" format="dimension"/>
+ <attr name="layout_wideParentWidth" format="dimension"/>
+ <attr name="layout_wideWidth" format="dimension"/>
+ <attr name="layout_wideMarginLeft" format="dimension"/>
+ <attr name="layout_wideMarginRight" format="dimension"/>
+ <attr name="layout_widePaddingLeft" format="dimension"/>
+ <attr name="layout_widePaddingRight" format="dimension"/>
+ </declare-styleable>
+
+ <declare-styleable name="ProportionalLayout">
+ <attr name="direction" format="string"/>
+ <attr name="ratio" format="float"/>
+ </declare-styleable>
+
+ <declare-styleable name="TransitionAnimationView">
+ <attr name="clipMarginLeft" format="dimension"/>
+ <attr name="clipMarginRight" format="dimension"/>
+ <attr name="clipMarginTop" format="dimension"/>
+ <attr name="clipMarginBottom" format="dimension"/>
+ <attr name="enterAnimation" format="reference"/>
+ <attr name="exitAnimation" format="reference"/>
+ <attr name="animationDuration" format="integer"/>
+ </declare-styleable>
+
+ <declare-styleable name="ContactBrowser">
+ <attr name="contact_filter_popup_width" format="dimension"/>
+ </declare-styleable>
+
+ <declare-styleable name="ContactListItemView">
+ <attr name="list_item_height" format="dimension"/>
+ <attr name="list_section_header_height" format="dimension"/>
+ <attr name="activated_background" format="reference"/>
+ <attr name="section_header_background" format="reference"/>
+ <attr name="list_item_divider" format="reference"/>
+ <attr name="list_item_padding_top" format="dimension"/>
+ <attr name="list_item_padding_right" format="dimension"/>
+ <attr name="list_item_padding_bottom" format="dimension"/>
+ <attr name="list_item_padding_left" format="dimension"/>
+ <attr name="list_item_gap_between_image_and_text" format="dimension"/>
+ <attr name="list_item_gap_between_label_and_data" format="dimension"/>
+ <attr name="list_item_call_button_padding" format="dimension"/>
+ <attr name="list_item_vertical_divider_margin" format="dimension"/>
+ <attr name="list_item_presence_icon_margin" format="dimension"/>
+ <attr name="list_item_presence_icon_size" format="dimension"/>
+ <attr name="list_item_photo_size" format="dimension"/>
+ <attr name="list_item_profile_photo_size" format="dimension"/>
+ <attr name="list_item_prefix_highlight_color" format="color"/>
+ <attr name="list_item_header_text_indent" format="dimension" />
+ <attr name="list_item_header_text_color" format="color" />
+ <attr name="list_item_header_text_size" format="dimension" />
+ <attr name="list_item_header_height" format="dimension" />
+ <attr name="list_item_header_underline_height" format="dimension" />
+ <attr name="list_item_header_underline_color" format="color" />
+ </declare-styleable>
+
+ <declare-styleable name="CallDetailActivity">
+ <attr name="call_detail_transparent_background" format="color" />
+ <attr name="call_detail_contact_background_overlay_alpha" format="float" />
+ </declare-styleable>
+
+ <declare-styleable name="CallLog">
+ <attr name="call_log_primary_text_color" format="color" />
+ <attr name="call_log_primary_background_color" format="color" />
+ <attr name="call_log_secondary_text_color" format="color" />
+ <attr name="call_log_secondary_background_color" format="color" />
+ <attr name="call_log_header_color" format="color" />
+ </declare-styleable>
+
+ <declare-styleable name="VoicemailStatus">
+ <attr name="call_log_voicemail_status_height" format="dimension" />
+ <attr name="call_log_voicemail_status_background_color" format="color" />
+ <attr name="call_log_voicemail_status_text_color" format="color" />
+ </declare-styleable>
+
+ <declare-styleable name="Favorites">
+ <attr name="favorites_padding_bottom" format="dimension" />
+ </declare-styleable>
</resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 325d2e7..b6b3f31 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -35,6 +35,8 @@
<color name="social_update_attribution_color">#ff777777</color>
+ <color name="social_update_comments_color">#ff777777</color>
+
<!-- Color used for the letter in the A-Z section header -->
<color name="section_header_text_color">#ff999999</color>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 45aa75e..cbac941 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -34,14 +34,6 @@
based on the source of the request -->
<dimen name="quick_contact_top_position">48dip</dimen>
- <!-- Width of the picture in the QuickContact popup. This can be -1 for the full width
- of the parent -->
- <dimen name="quick_contact_picture_width">-1px</dimen>
-
- <!-- Height of the picture in the QuickContact popup. This can be -1 for the full height
- of the parent -->
- <dimen name="quick_contact_picture_height">174dip</dimen>
-
<!-- Padding of the rounded plus/minus/expand/collapse buttons in the editor -->
<dimen name="editor_round_button_padding_left">2dip</dimen>
<dimen name="editor_round_button_padding_right">2dip</dimen>
@@ -93,9 +85,6 @@
<!-- Margin between the photo, the star, and text in the contact detail header view -->
<dimen name="detail_header_view_margin">8dip</dimen>
- <!-- Height of the tab carousel on the contact detail page -->
- <dimen name="detail_tab_carousel_height">150dip</dimen>
-
<!-- Height of the tab text label in the tab carousel on the contact detail page -->
<dimen name="detail_tab_carousel_tab_label_height">48dip</dimen>
@@ -120,8 +109,8 @@
<!-- Vertical padding above and below individual stream items -->
<dimen name="detail_update_section_item_vertical_padding">16dip</dimen>
- <!-- Left-side padding for individual stream items -->
- <dimen name="detail_update_section_item_left_padding">8dip</dimen>
+ <!-- Horizontal padding for individual stream items -->
+ <dimen name="detail_update_section_item_horizontal_padding">24dip</dimen>
<!-- Horizontal padding between content sections within a stream item -->
<dimen name="detail_update_section_internal_padding">16dip</dimen>
@@ -144,15 +133,16 @@
<!-- Minimum height of a row in the contact detail -->
<dimen name="detail_min_line_item_height">48dip</dimen>
- <!-- Width of a contact detail item type (i.e. Nickname or Website). -->
- <dimen name="detail_item_type_width">164dip</dimen>
-
<!-- Width of height of an icon from a third-party app in the networks section of the contact card. -->
<dimen name="detail_network_icon_size">32dip</dimen>
<!-- Font size for the display name in header of the contact detail page -->
<dimen name="detail_header_name_text_size">36sp</dimen>
+ <!-- Vertical margin for vertical dividers existing between primary data
+ (phone number, email, etc.) and a secondary action button -->
+ <dimen name="detail_vertical_divider_vertical_margin">16dip</dimen>
+
<!-- Padding to be used between a visible scrollbar and the contact list -->
<dimen name="list_visible_scrollbar_padding">40dip</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 999531e..b1f9f6f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1019,8 +1019,8 @@
was found that could perform the selected action -->
<string name="quickcontact_missing_app">No application found to handle this action</string>
- <!-- Shown as the header name for a person when the name is missing or unknown. -->
- <string name="quickcontact_missing_name">Unknown</string>
+ <!-- Shown as the display name for a person when the name is missing or unknown. [CHAR LIMIT=18]-->
+ <string name="missing_name">(no name)</string>
<!-- The menu item to open the list of accounts -->
<string name="menu_accounts">Accounts</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 785c887..6bc5582 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -15,8 +15,9 @@
-->
<resources>
<style name="DialtactsTheme"
- parent="android:Theme.Holo.SolidActionBar.SplitActionBarWhenNarrow">
+ parent="android:Theme.Holo.SplitActionBarWhenNarrow">
<item name="android:windowActionBarOverlay">true</item>
+ <item name="android:actionBarStyle">@style/DialtactsActionBarStyle</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowBackground">@android:color/black</item>
<item name="activated_background">@drawable/list_item_activated_background</item>
@@ -58,6 +59,7 @@
</style>
<style name="CallDetailActivityTheme" parent="android:Theme.Holo.SplitActionBarWhenNarrow">
+ <item name="android:windowBackground">@android:color/black</item>
<item name="android:gravity">top</item>
<item name="call_detail_transparent_background">#CC000000</item>
<item name="call_detail_contact_background_overlay_alpha">0.25</item>
@@ -115,60 +117,6 @@
<item name="android:windowExitAnimation">@anim/dummy_animation</item>
</style>
- <declare-styleable name="ContactBrowser">
- <attr name="contact_filter_popup_width" format="dimension"/>
- </declare-styleable>
-
- <declare-styleable name="ContactListItemView">
- <attr name="list_item_height" format="dimension"/>
- <attr name="list_section_header_height" format="dimension"/>
- <attr name="activated_background" format="reference"/>
- <attr name="section_header_background" format="reference"/>
- <attr name="list_item_divider" format="reference"/>
- <attr name="list_item_padding_top" format="dimension"/>
- <attr name="list_item_padding_right" format="dimension"/>
- <attr name="list_item_padding_bottom" format="dimension"/>
- <attr name="list_item_padding_left" format="dimension"/>
- <attr name="list_item_gap_between_image_and_text" format="dimension"/>
- <attr name="list_item_gap_between_label_and_data" format="dimension"/>
- <attr name="list_item_call_button_padding" format="dimension"/>
- <attr name="list_item_vertical_divider_margin" format="dimension"/>
- <attr name="list_item_presence_icon_margin" format="dimension"/>
- <attr name="list_item_presence_icon_size" format="dimension"/>
- <attr name="list_item_photo_size" format="dimension"/>
- <attr name="list_item_profile_photo_size" format="dimension"/>
- <attr name="list_item_prefix_highlight_color" format="color"/>
- <attr name="list_item_header_text_indent" format="dimension" />
- <attr name="list_item_header_text_color" format="color" />
- <attr name="list_item_header_text_size" format="dimension" />
- <attr name="list_item_header_height" format="dimension" />
- <attr name="list_item_header_underline_height" format="dimension" />
- <attr name="list_item_header_underline_color" format="color" />
- </declare-styleable>
-
- <declare-styleable name="CallDetailActivity">
- <attr name="call_detail_transparent_background" format="color" />
- <attr name="call_detail_contact_background_overlay_alpha" format="float" />
- </declare-styleable>
-
- <declare-styleable name="CallLog">
- <attr name="call_log_primary_text_color" format="color" />
- <attr name="call_log_primary_background_color" format="color" />
- <attr name="call_log_secondary_text_color" format="color" />
- <attr name="call_log_secondary_background_color" format="color" />
- <attr name="call_log_header_color" format="color" />
- </declare-styleable>
-
- <declare-styleable name="VoicemailStatus">
- <attr name="call_log_voicemail_status_height" format="dimension" />
- <attr name="call_log_voicemail_status_background_color" format="color" />
- <attr name="call_log_voicemail_status_text_color" format="color" />
- </declare-styleable>
-
- <declare-styleable name="Favorites">
- <attr name="favorites_padding_bottom" format="dimension" />
- </declare-styleable>
-
<style name="PeopleTheme" parent="@android:style/Theme.Holo.Light.SolidActionBar.Inverse.SplitActionBarWhenNarrow">
<item name="android:actionBarStyle">@style/ContactsActionBarStyle</item>
<item name="list_item_height">?android:attr/listPreferredItemHeight</item>
@@ -270,31 +218,6 @@
<item name="android:layout_height">match_parent</item>
</style>
- <declare-styleable name="InterpolatingLayout_Layout">
- <attr name="layout_narrowParentWidth" format="dimension"/>
- <attr name="layout_narrowWidth" format="dimension"/>
- <attr name="layout_narrowMarginLeft" format="dimension"/>
- <attr name="layout_narrowMarginRight" format="dimension"/>
- <attr name="layout_narrowPaddingLeft" format="dimension"/>
- <attr name="layout_narrowPaddingRight" format="dimension"/>
- <attr name="layout_wideParentWidth" format="dimension"/>
- <attr name="layout_wideWidth" format="dimension"/>
- <attr name="layout_wideMarginLeft" format="dimension"/>
- <attr name="layout_wideMarginRight" format="dimension"/>
- <attr name="layout_widePaddingLeft" format="dimension"/>
- <attr name="layout_widePaddingRight" format="dimension"/>
- </declare-styleable>
-
- <declare-styleable name="TransitionAnimationView">
- <attr name="clipMarginLeft" format="dimension"/>
- <attr name="clipMarginRight" format="dimension"/>
- <attr name="clipMarginTop" format="dimension"/>
- <attr name="clipMarginBottom" format="dimension"/>
- <attr name="enterAnimation" format="reference"/>
- <attr name="exitAnimation" format="reference"/>
- <attr name="animationDuration" format="integer"/>
- </declare-styleable>
-
<style name="DirectoryHeader" parent="PeopleTheme">
<item name="android:background">@drawable/directory_bg</item>
</style>
@@ -372,4 +295,10 @@
<item name="android:alpha">0.5</item>
<item name="android:background">@android:color/black</item>
</style>
+
+ <style name="DialtactsActionBarStyle" parent="android:Widget.Holo.ActionBar">
+ <item name="android:backgroundSplit">@drawable/ab_bottom_opaque_dark_holo</item>
+ <item name="android:backgroundStacked">@drawable/ab_stacked_opaque_dark_holo</item>
+ </style>
+
</resources>
diff --git a/src/com/android/contacts/activities/ActionBarAdapter.java b/src/com/android/contacts/activities/ActionBarAdapter.java
index 6d28235..5a32d74 100644
--- a/src/com/android/contacts/activities/ActionBarAdapter.java
+++ b/src/com/android/contacts/activities/ActionBarAdapter.java
@@ -31,6 +31,7 @@
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.inputmethod.InputMethodManager;
import android.widget.SearchView;
import android.widget.SearchView.OnCloseListener;
import android.widget.SearchView.OnQueryTextListener;
@@ -112,6 +113,12 @@
}
LayoutParams layoutParams = new LayoutParams(searchViewWidth, LayoutParams.WRAP_CONTENT);
mSearchView = (SearchView) customSearchView.findViewById(R.id.search_view);
+ // Since the {@link SearchView} in this app is "click-to-expand", set the below mode on the
+ // {@link SearchView} so that the magnifying glass icon appears inside the editable text
+ // field. (In the "click-to-expand" search pattern, the user must explicitly expand the
+ // search field and already knows a search is being conducted, so the icon is redundant
+ // and can go away once the user starts typing.)
+ mSearchView.setIconifiedByDefault(true);
mSearchView.setQueryHint(mContext.getString(R.string.hint_findContacts));
mSearchView.setOnQueryTextListener(this);
mSearchView.setOnCloseListener(this);
@@ -265,6 +272,9 @@
private void update() {
if (mSearchMode) {
setFocusOnSearchView();
+ // Since we have the {@link SearchView} in a custom action bar, we must manually handle
+ // expanding the {@link SearchView} when a search is initiated.
+ mSearchView.onActionViewExpanded();
if (mActionBar.getNavigationMode() != ActionBar.NAVIGATION_MODE_STANDARD) {
mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
}
@@ -287,6 +297,9 @@
mTabListener.mIgnoreTabSelected = false;
}
mActionBar.setTitle(null);
+ // Since we have the {@link SearchView} in a custom action bar, we must manually handle
+ // collapsing the {@link SearchView} when search mode is exited.
+ mSearchView.onActionViewCollapsed();
if (mListener != null) {
mListener.onAction(Action.STOP_SEARCH_MODE);
mListener.onSelectedTabChanged();
@@ -317,6 +330,16 @@
@Override
public boolean onQueryTextSubmit(String query) {
+ // When the search is "committed" by the user, then hide the keyboard so the user can
+ // more easily browse the list of results.
+ if (mSearchView != null) {
+ InputMethodManager imm = (InputMethodManager) mContext.getSystemService(
+ Context.INPUT_METHOD_SERVICE);
+ if (imm != null) {
+ imm.hideSoftInputFromWindow(mSearchView.getWindowToken(), 0);
+ }
+ mSearchView.clearFocus();
+ }
return true;
}
diff --git a/src/com/android/contacts/activities/ContactDetailActivity.java b/src/com/android/contacts/activities/ContactDetailActivity.java
index 6046f5e..02b7bac 100644
--- a/src/com/android/contacts/activities/ContactDetailActivity.java
+++ b/src/com/android/contacts/activities/ContactDetailActivity.java
@@ -65,6 +65,13 @@
public class ContactDetailActivity extends ContactsActivity {
private static final String TAG = "ContactDetailActivity";
+ /**
+ * Intent key for a boolean that specifies whether the "up" afforance in this activity should
+ * behave as default (return user back to {@link PeopleActivity}) or whether the activity should
+ * instead be finished.
+ */
+ public static final String INTENT_KEY_IGNORE_DEFAULT_UP_BEHAVIOR = "ignoreDefaultUpBehavior";
+
private static final String KEY_DETAIL_FRAGMENT_TAG = "detailFragTag";
private static final String KEY_UPDATES_FRAGMENT_TAG = "updatesFragTag";
@@ -72,6 +79,7 @@
private ContactLoader.Result mContactData;
private Uri mLookupUri;
+ private boolean mIgnoreDefaultUpBehavior;
private ContactLoaderFragment mLoaderFragment;
private ContactDetailFragment mDetailFragment;
@@ -114,6 +122,9 @@
return;
}
+ mIgnoreDefaultUpBehavior = getIntent().getBooleanExtra(
+ INTENT_KEY_IGNORE_DEFAULT_UP_BEHAVIOR, false);
+
setContentView(R.layout.contact_detail_activity);
mRootView = (ViewGroup) findViewById(R.id.contact_detail_view);
mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -529,6 +540,10 @@
switch (item.getItemId()) {
case android.R.id.home:
+ if (mIgnoreDefaultUpBehavior) {
+ finish();
+ return true;
+ }
Intent intent = new Intent(this, PeopleActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
diff --git a/src/com/android/contacts/activities/DialpadActivity.java b/src/com/android/contacts/activities/DialpadActivity.java
index cfe17f3..1221068 100644
--- a/src/com/android/contacts/activities/DialpadActivity.java
+++ b/src/com/android/contacts/activities/DialpadActivity.java
@@ -64,7 +64,7 @@
@Override
protected void onNewIntent(Intent newIntent) {
setIntent(newIntent);
- mFragment.resolveIntent(newIntent);
+ mFragment.configureScreenFromIntent(newIntent);
}
public DialpadFragment getFragment() {
diff --git a/src/com/android/contacts/activities/DialtactsActivity.java b/src/com/android/contacts/activities/DialtactsActivity.java
index 01212f5..2040f8d 100644
--- a/src/com/android/contacts/activities/DialtactsActivity.java
+++ b/src/com/android/contacts/activities/DialtactsActivity.java
@@ -481,12 +481,18 @@
final String action = newIntent.getAction();
if (UI.FILTER_CONTACTS_ACTION.equals(action)) {
setupFilterText(newIntent);
- } else if (isDialIntent(newIntent)) {
- setupDialUri(newIntent);
}
if (mInSearchUi || mSearchFragment.isVisible()) {
exitSearchUi();
}
+
+ if (mViewPager.getCurrentItem() == TAB_INDEX_DIALER) {
+ if (mDialpadFragment != null) {
+ mDialpadFragment.configureScreenFromIntent(newIntent);
+ } else {
+ Log.e(TAG, "DialpadFragment isn't ready yet when the tab is already selected.");
+ }
+ }
}
/** Returns true if the given intent contains a phone number to populate the dialer with */
@@ -535,33 +541,6 @@
}
}
- /**
- * Retrieves the uri stored in {@link #setupDialUri(Intent)}. This uri
- * originally came from a dial intent received by this activity. The stored
- * uri will then be cleared after after this method returns.
- *
- * @return The stored uri
- */
- public Uri getAndClearDialUri() {
- Uri dialUri = mDialUri;
- mDialUri = null;
- return dialUri;
- }
-
- /**
- * Stores the uri associated with a dial intent. This is so child activities can
- * check if they are supposed to display new dial info.
- *
- * @param intent The intent received in {@link #onNewIntent(Intent)}
- */
- private void setupDialUri(Intent intent) {
- // If the intent was relaunched from history, don't reapply the intent.
- if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
- return;
- }
- mDialUri = intent.getData();
- }
-
@Override
public void onBackPressed() {
if (mInSearchUi) {
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 6dc727e..48fd49d 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -961,7 +961,15 @@
if (PhoneCapabilityTester.isUsingTwoPanes(PeopleActivity.this)) {
setupContactDetailFragment(contactLookupUri);
} else {
- startActivity(new Intent(Intent.ACTION_VIEW, contactLookupUri));
+ Intent intent = new Intent(Intent.ACTION_VIEW, contactLookupUri);
+ // In search mode, the "up" affordance in the contact detail page should return the
+ // user to the search results, so suppress the normal behavior which would re-launch
+ // {@link PeopleActivity} when the "up" affordance is clicked.
+ if (mActionBarAdapter.isSearchMode()) {
+ intent.putExtra(ContactDetailActivity.INTENT_KEY_IGNORE_DEFAULT_UP_BEHAVIOR,
+ true);
+ }
+ startActivity(intent);
}
}
diff --git a/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java b/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java
index e55020c..26275af 100644
--- a/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java
+++ b/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java
@@ -84,7 +84,7 @@
DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_SHOW_YEAR);
dateView.setText(dateValue);
// Set the duration
- if (callType == Calls.MISSED_TYPE) {
+ if (callType == Calls.MISSED_TYPE || callType == Calls.VOICEMAIL_TYPE) {
durationView.setVisibility(View.GONE);
} else {
durationView.setVisibility(View.VISIBLE);
diff --git a/src/com/android/contacts/calllog/CallLogNotificationsService.java b/src/com/android/contacts/calllog/CallLogNotificationsService.java
index eda11d6..6dd24aa 100644
--- a/src/com/android/contacts/calllog/CallLogNotificationsService.java
+++ b/src/com/android/contacts/calllog/CallLogNotificationsService.java
@@ -18,25 +18,55 @@
import android.app.IntentService;
import android.content.Intent;
+import android.net.Uri;
import android.util.Log;
/**
* Provides operations for managing notifications.
* <p>
- * At the moment, it only handle {@link #ACTION_MARK_NEW_CALLS_AS_OLD}, which marks all the new
- * items in the call log as old; this is called when a notification is dismissed.
+ * It handles the following actions:
+ * <ul>
+ * <li>{@link #ACTION_MARK_NEW_CALLS_AS_OLD}: marks all the new items in the call log as old; this
+ * is called when a notification is dismissed.</li>
+ * <li>{@link #ACTION_UPDATE_NOTIFICATIONS}: updates the content of the new items notification; it
+ * may include an optional extra {@link #EXTRA_NEW_VOICEMAIL_URI}, containing the URI of the new
+ * voicemail that has triggered this update (if any).</li>
+ * </ul>
*/
public class CallLogNotificationsService extends IntentService {
private static final String TAG = "CallLogNotificationsService";
- // Action to mark all the new calls as old. Invoked when the notifications need to be cleared.
+ /**
+ * Action to mark all the new calls as old.
+ */
public static final String ACTION_MARK_NEW_CALLS_AS_OLD =
- "com.android.contacts.ACTION_MARK_NEW_CALLS_AS_OLD";
+ "com.android.contacts.calllog.MARK_NEW_CALLS_AS_OLD";
+
+ /**
+ * Action to update the notifications.
+ * <p>
+ * May include an optional extra {@link #EXTRA_NEW_VOICEMAIL_URI}.
+ */
+ public static final String ACTION_UPDATE_NOTIFICATIONS =
+ "com.android.contacts.calllog.UPDATE_NOTIFICATIONS";
+
+ /**
+ * Extra to included with {@link #ACTION_UPDATE_NOTIFICATIONS} to identify the new voicemail
+ * that triggered an update.
+ * <p>
+ * It must be a {@link Uri}.
+ */
+ public static final String EXTRA_NEW_VOICEMAIL_URI = "NEW_VOICEMAIL_URI";
private CallLogQueryHandler mCallLogQueryHandler;
public CallLogNotificationsService() {
super("CallLogNotificationsService");
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
mCallLogQueryHandler = new CallLogQueryHandler(getContentResolver(), null /*listener*/);
}
@@ -44,10 +74,11 @@
protected void onHandleIntent(Intent intent) {
if (ACTION_MARK_NEW_CALLS_AS_OLD.equals(intent.getAction())) {
mCallLogQueryHandler.markNewCallsAsOld();
- return;
+ } else if (ACTION_UPDATE_NOTIFICATIONS.equals(intent.getAction())) {
+ Uri voicemailUri = (Uri) intent.getParcelableExtra(EXTRA_NEW_VOICEMAIL_URI);
+ DefaultVoicemailNotifier.getInstance(this).updateNotification(voicemailUri);
} else {
Log.d(TAG, "onHandleIntent: could not handle: " + intent);
}
}
-
}
diff --git a/src/com/android/contacts/calllog/CallLogReceiver.java b/src/com/android/contacts/calllog/CallLogReceiver.java
index a3ff1f2..14bfa64 100644
--- a/src/com/android/contacts/calllog/CallLogReceiver.java
+++ b/src/com/android/contacts/calllog/CallLogReceiver.java
@@ -16,9 +16,7 @@
package com.android.contacts.calllog;
-import android.app.NotificationManager;
import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.provider.VoicemailContract;
@@ -33,29 +31,20 @@
public class CallLogReceiver extends BroadcastReceiver {
private static final String TAG = "CallLogReceiver";
- private VoicemailNotifier mNotifier;
-
@Override
public void onReceive(Context context, Intent intent) {
- if (mNotifier == null) {
- mNotifier = getNotifier(context);
- }
if (VoicemailContract.ACTION_NEW_VOICEMAIL.equals(intent.getAction())) {
- mNotifier.notifyNewVoicemail(intent.getData());
+ Intent serviceIntent = new Intent(context, CallLogNotificationsService.class);
+ serviceIntent.setAction(CallLogNotificationsService.ACTION_UPDATE_NOTIFICATIONS);
+ serviceIntent.putExtra(
+ CallLogNotificationsService.EXTRA_NEW_VOICEMAIL_URI, intent.getData());
+ context.startService(serviceIntent);
} else if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
- mNotifier.updateNotification();
+ Intent serviceIntent = new Intent(context, CallLogNotificationsService.class);
+ serviceIntent.setAction(CallLogNotificationsService.ACTION_UPDATE_NOTIFICATIONS);
+ context.startService(serviceIntent);
} else {
- Log.d(TAG, "onReceive: could not handle: " + intent);
+ Log.w(TAG, "onReceive: could not handle: " + intent);
}
}
-
- private VoicemailNotifier getNotifier(Context context) {
- NotificationManager notificationManager =
- (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- ContentResolver contentResolver = context.getContentResolver();
- return new DefaultVoicemailNotifier(context, notificationManager,
- DefaultVoicemailNotifier.createNewCallsQuery(contentResolver),
- DefaultVoicemailNotifier.createNameLookupQuery(contentResolver),
- DefaultVoicemailNotifier.createPhoneNumberHelper(context));
- }
}
diff --git a/src/com/android/contacts/calllog/DefaultVoicemailNotifier.java b/src/com/android/contacts/calllog/DefaultVoicemailNotifier.java
index bb0b0f3..1cf67c1 100644
--- a/src/com/android/contacts/calllog/DefaultVoicemailNotifier.java
+++ b/src/com/android/contacts/calllog/DefaultVoicemailNotifier.java
@@ -51,13 +51,30 @@
/** The identifier of the notification of new voicemails. */
private static final int NOTIFICATION_ID = 1;
+ /** The singleton instance of {@link DefaultVoicemailNotifier}. */
+ private static DefaultVoicemailNotifier sInstance;
+
private final Context mContext;
private final NotificationManager mNotificationManager;
private final NewCallsQuery mNewCallsQuery;
private final NameLookupQuery mNameLookupQuery;
private final PhoneNumberHelper mPhoneNumberHelper;
- public DefaultVoicemailNotifier(Context context,
+ /** Returns the singleton instance of the {@link DefaultVoicemailNotifier}. */
+ public static synchronized DefaultVoicemailNotifier getInstance(Context context) {
+ if (sInstance == null) {
+ NotificationManager notificationManager =
+ (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ ContentResolver contentResolver = context.getContentResolver();
+ sInstance = new DefaultVoicemailNotifier(context, notificationManager,
+ createNewCallsQuery(contentResolver),
+ createNameLookupQuery(contentResolver),
+ createPhoneNumberHelper(context));
+ }
+ return sInstance;
+ }
+
+ private DefaultVoicemailNotifier(Context context,
NotificationManager notificationManager, NewCallsQuery newCallsQuery,
NameLookupQuery nameLookupQuery, PhoneNumberHelper phoneNumberHelper) {
mContext = context;
@@ -67,20 +84,9 @@
mPhoneNumberHelper = phoneNumberHelper;
}
- @Override
- public void notifyNewVoicemail(Uri newVoicemailUri) {
- Log.d(TAG, "notifyNewVoicemail: " + newVoicemailUri);
- updateNotification(newVoicemailUri);
- }
-
- @Override
- public void updateNotification() {
- Log.d(TAG, "updateNotification");
- updateNotification(null);
- }
-
/** Updates the notification and notifies of the call with the given URI. */
- private void updateNotification(Uri newCallUri) {
+ @Override
+ public void updateNotification(Uri newCallUri) {
// Lookup the list of new voicemails to include in the notification.
// TODO: Move this into a service, to avoid holding the receiver up.
final NewCall[] newCalls = mNewCallsQuery.query();
diff --git a/src/com/android/contacts/calllog/VoicemailNotifier.java b/src/com/android/contacts/calllog/VoicemailNotifier.java
index 1ac949d..8d45486 100644
--- a/src/com/android/contacts/calllog/VoicemailNotifier.java
+++ b/src/com/android/contacts/calllog/VoicemailNotifier.java
@@ -23,17 +23,15 @@
*/
public interface VoicemailNotifier {
/**
- * Notifies the user of a new voicemail.
+ * Updates the notification and clears it if there are no new voicemails.
+ * <p>
+ * If the given URI corresponds to a new voicemail, also notifies about it.
+ * <p>
+ * It is not safe to call this method from the main thread.
*
- * @param newVoicemailUri URI of the new voicemail record just inserted
+ * @param newCallUri URI of the new call, may be null
*/
- public void notifyNewVoicemail(Uri newVoicemailUri);
-
- /**
- * Updates the notification and clears it if there are no new voicemails. Called when the phone
- * just rebooted to put back notifications for anything the user has not acknowledged.
- */
- public void updateNotification();
+ public void updateNotification(Uri newCallUri);
/** Clears the new voicemail notification. */
public void clearNotification();
diff --git a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
index e9d75ef..7144dfb 100644
--- a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
+++ b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
@@ -25,6 +25,7 @@
import com.android.contacts.util.ContactBadgeUtil;
import com.android.contacts.util.StreamItemEntry;
import com.android.contacts.util.StreamItemPhotoEntry;
+import com.google.common.annotations.VisibleForTesting;
import android.content.ContentValues;
import android.content.Context;
@@ -98,6 +99,8 @@
styledName = altDisplayName;
}
}
+ } else {
+ styledName = context.getResources().getString(R.string.missing_name);
}
return styledName;
}
@@ -250,24 +253,33 @@
* Displays the social stream items under the given layout.
*/
public static void showSocialStreamItems(LayoutInflater inflater, Context context,
- Result contactData, LinearLayout streamContainer) {
+ Result contactData, LinearLayout streamContainer, View.OnClickListener listener) {
if (streamContainer != null) {
streamContainer.removeAllViews();
List<StreamItemEntry> streamItems = contactData.getStreamItems();
for (StreamItemEntry streamItem : streamItems) {
- addStreamItemToContainer(inflater, context, streamItem, streamContainer);
+ addStreamItemToContainer(inflater, context, streamItem, streamContainer, listener);
}
}
}
- public static void addStreamItemToContainer(LayoutInflater inflater, Context context,
- StreamItemEntry streamItem, LinearLayout streamContainer) {
+ @VisibleForTesting
+ static void addStreamItemToContainer(LayoutInflater inflater, Context context,
+ StreamItemEntry streamItem, LinearLayout streamContainer,
+ View.OnClickListener listener) {
View oneColumnView = inflater.inflate(R.layout.stream_item_one_column,
streamContainer, false);
ViewGroup contentBox = (ViewGroup) oneColumnView.findViewById(R.id.stream_item_content);
int internalPadding = context.getResources().getDimensionPixelSize(
R.dimen.detail_update_section_internal_padding);
+ // Add the listener only if there is an action and corresponding URI.
+ if (streamItem.getAction() != null && streamItem.getActionUri() != null) {
+ contentBox.setTag(streamItem);
+ contentBox.setOnClickListener(listener);
+ contentBox.setFocusable(true);
+ }
+
// TODO: This is not the correct layout for a stream item with photos. Photos should be
// displayed first, then the update text either to the right of the final image (if there
// are an odd number of images) or below the last row of images (if there are an even
@@ -327,14 +339,22 @@
streamContainer.addView(oneColumnView);
}
- private static View addStreamItemText(LayoutInflater inflater, Context context,
+ @VisibleForTesting
+ static View addStreamItemText(LayoutInflater inflater, Context context,
StreamItemEntry streamItem, ViewGroup parent) {
View textUpdate = inflater.inflate(R.layout.stream_item_text, parent, false);
TextView htmlView = (TextView) textUpdate.findViewById(R.id.stream_item_html);
TextView attributionView = (TextView) textUpdate.findViewById(
R.id.stream_item_attribution);
+ TextView commentsView = (TextView) textUpdate.findViewById(R.id.stream_item_comments);
htmlView.setText(Html.fromHtml(streamItem.getText()));
attributionView.setText(ContactBadgeUtil.getSocialDate(streamItem, context));
+ if (streamItem.getComments() != null) {
+ commentsView.setText(Html.fromHtml(streamItem.getComments()));
+ commentsView.setVisibility(View.VISIBLE);
+ } else {
+ commentsView.setVisibility(View.GONE);
+ }
parent.addView(textUpdate);
return textUpdate;
}
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index 946fbe8..c3b2de6 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -117,7 +117,7 @@
import java.util.Map;
public class ContactDetailFragment extends Fragment implements FragmentKeyListener, ViewOverlay,
- OnItemClickListener, SelectAccountDialogFragment.Listener {
+ SelectAccountDialogFragment.Listener {
private static final String TAG = "ContactDetailFragment";
@@ -264,8 +264,7 @@
mListView = (ListView) mView.findViewById(android.R.id.list);
mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY);
- mListView.setOnItemClickListener(this);
- registerForContextMenu(mListView);
+ mListView.setItemsCanFocus(true);
mListView.setOnScrollListener(mVerticalScrollListener);
// Don't set it to mListView yet. We do so later when we bind the adapter.
@@ -1331,29 +1330,37 @@
* {@link DetailViewEntry}
*/
private static class DetailViewCache {
- public TextView kind;
- public TextView type;
- public TextView data;
- public TextView footer;
- public ImageView presenceIcon;
- public ImageView secondaryActionButton;
- public View secondaryActionButtonContainer;
- public View secondaryActionDivider;
- public View primaryIndicator;
+ public final TextView kind;
+ public final TextView type;
+ public final TextView data;
+ public final TextView footer;
+ public final ImageView presenceIcon;
+ public final ImageView secondaryActionButton;
+ public final View primaryActionViewContainer;
+ public final View secondaryActionViewContainer;
+ public final View secondaryActionDivider;
+ public final View primaryIndicator;
- public DetailViewCache(View view, OnClickListener secondaryActionClickListener) {
+ public DetailViewCache(View view,
+ OnClickListener primaryActionClickListener,
+ OnClickListener secondaryActionClickListener) {
kind = (TextView) view.findViewById(R.id.kind);
type = (TextView) view.findViewById(R.id.type);
data = (TextView) view.findViewById(R.id.data);
footer = (TextView) view.findViewById(R.id.footer);
primaryIndicator = view.findViewById(R.id.primary_indicator);
presenceIcon = (ImageView) view.findViewById(R.id.presence_icon);
+
+ primaryActionViewContainer = view.findViewById(R.id.primary_action_view_container);
+ primaryActionViewContainer.setOnClickListener(primaryActionClickListener);
+
+ secondaryActionViewContainer = view.findViewById(
+ R.id.secondary_action_view_container);
+ secondaryActionViewContainer.setOnClickListener(
+ secondaryActionClickListener);
secondaryActionButton = (ImageView) view.findViewById(
R.id.secondary_action_button);
- secondaryActionButtonContainer = view.findViewById(
- R.id.secondary_action_button_container);
- secondaryActionButtonContainer.setOnClickListener(
- secondaryActionClickListener);
+
secondaryActionDivider = view.findViewById(R.id.vertical_divider);
}
}
@@ -1494,15 +1501,16 @@
v = mInflater.inflate(R.layout.contact_detail_list_item, parent, false);
// Cache the children
- viewCache = new DetailViewCache(v, mSecondaryActionClickListener);
+ viewCache = new DetailViewCache(v,
+ mPrimaryActionClickListener, mSecondaryActionClickListener);
v.setTag(viewCache);
}
- bindDetailView(v, entry);
+ bindDetailView(position, v, entry);
return v;
}
- private void bindDetailView(View view, DetailViewEntry entry) {
+ private void bindDetailView(int position, View view, DetailViewEntry entry) {
final Resources resources = mContext.getResources();
DetailViewCache views = (DetailViewCache) view.getTag();
@@ -1538,6 +1546,12 @@
presenceIconView.setVisibility(View.GONE);
}
+ final PrimaryActionViewContainer primaryActionButtonContainer =
+ (PrimaryActionViewContainer) views.primaryActionViewContainer;
+ primaryActionButtonContainer.setTag(entry);
+ primaryActionButtonContainer.setPosition(position);
+ registerForContextMenu(primaryActionButtonContainer);
+
// Set the secondary action button
final ImageView secondaryActionView = views.secondaryActionButton;
Drawable secondaryActionIcon = null;
@@ -1551,20 +1565,30 @@
resources.getDrawable(R.drawable.sym_action_audiochat_holo_light);
}
+ final View secondaryActionViewContainer = views.secondaryActionViewContainer;
if (entry.secondaryIntent != null && secondaryActionIcon != null) {
secondaryActionView.setImageDrawable(secondaryActionIcon);
- views.secondaryActionButtonContainer.setTag(entry);
- views.secondaryActionButtonContainer.setVisibility(View.VISIBLE);
+ secondaryActionViewContainer.setTag(entry);
+ secondaryActionViewContainer.setVisibility(View.VISIBLE);
views.secondaryActionDivider.setVisibility(View.VISIBLE);
} else {
- views.secondaryActionButtonContainer.setVisibility(View.GONE);
+ secondaryActionViewContainer.setVisibility(View.GONE);
views.secondaryActionDivider.setVisibility(View.GONE);
}
- view.setPadding(entry.isInSubSection() ? mViewEntryDimensions.getWidePaddingLeft() :
- mViewEntryDimensions.getPaddingLeft(),
+ // Right padding should not have "pressed" effect.
+ view.setPadding(0, 0, mViewEntryDimensions.getPaddingRight(), 0);
+ // Top, left, and bottom paddings should have "pressed" effect.
+ primaryActionButtonContainer.setPadding(entry.isInSubSection() ?
+ mViewEntryDimensions.getWidePaddingLeft() :
+ mViewEntryDimensions.getPaddingLeft(),
mViewEntryDimensions.getPaddingTop(),
- mViewEntryDimensions.getPaddingRight(),
+ 0,
+ mViewEntryDimensions.getPaddingBottom());
+ secondaryActionViewContainer.setPadding(
+ secondaryActionViewContainer.getPaddingLeft(),
+ mViewEntryDimensions.getPaddingTop(),
+ secondaryActionViewContainer.getPaddingRight(),
mViewEntryDimensions.getPaddingBottom());
}
@@ -1579,12 +1603,22 @@
}
}
- private OnClickListener mSecondaryActionClickListener = new OnClickListener() {
+ private final OnClickListener mPrimaryActionClickListener = new OnClickListener() {
@Override
- public void onClick(View v) {
+ public void onClick(View view) {
if (mListener == null) return;
- if (v == null) return;
- final ViewEntry entry = (ViewEntry) v.getTag();
+ final ViewEntry entry = (ViewEntry) view.getTag();
+ if (entry == null) return;
+ entry.click(view, mListener);
+ }
+ };
+
+ private final OnClickListener mSecondaryActionClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (mListener == null) return;
+ if (view == null) return;
+ final ViewEntry entry = (ViewEntry) view.getTag();
if (entry == null || !(entry instanceof DetailViewEntry)) return;
final DetailViewEntry detailViewEntry = (DetailViewEntry) entry;
final Intent intent = detailViewEntry.secondaryIntent;
@@ -1650,14 +1684,6 @@
}
@Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- if (mListener == null) return;
- final ViewEntry entry = mAdapter.getItem(position);
- if (entry == null) return;
- entry.click(view, mListener);
- }
-
- @Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
diff --git a/src/com/android/contacts/detail/ContactDetailTabCarousel.java b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
index 79ac5fb..4ef4b1c 100644
--- a/src/com/android/contacts/detail/ContactDetailTabCarousel.java
+++ b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
@@ -55,8 +55,6 @@
private CarouselTab mAboutTab;
private CarouselTab mUpdatesTab;
- private int mTabWidth;
- private int mTabHeight;
private int mTabDisplayLabelHeight;
private int mLastScrollPosition;
@@ -82,10 +80,8 @@
setOnTouchListener(this);
Resources resources = mContext.getResources();
- mTabHeight = resources.getDimensionPixelSize(R.dimen.detail_tab_carousel_height);
mTabDisplayLabelHeight = resources.getDimensionPixelSize(
R.dimen.detail_tab_carousel_tab_label_height);
- mAllowedVerticalScrollLength = mTabHeight - mTabDisplayLabelHeight;
}
@Override
@@ -117,26 +113,27 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- measureChildren(widthMeasureSpec);
- }
-
- private void measureChildren(int widthMeasureSpec) {
int screenWidth = MeasureSpec.getSize(widthMeasureSpec);
// Compute the width of a tab as a fraction of the screen width
- mTabWidth = (int) (TAB_WIDTH_SCREEN_PERCENTAGE * screenWidth);
+ int tabWidth = (int) (TAB_WIDTH_SCREEN_PERCENTAGE * screenWidth);
// Find the allowed scrolling length by subtracting the current visible screen width
// from the total length of the tabs.
- mAllowedHorizontalScrollLength = mTabWidth * TAB_COUNT - screenWidth;
+ mAllowedHorizontalScrollLength = tabWidth * TAB_COUNT - screenWidth;
+ int tabHeight = screenWidth / 2;
// Set the child {@link LinearLayout} to be TAB_COUNT * the computed tab width so that the
// {@link LinearLayout}'s children (which are the tabs) will evenly split that width.
if (getChildCount() > 0) {
View child = getChildAt(0);
- child.measure(MeasureSpec.makeMeasureSpec(TAB_COUNT * mTabWidth, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(mTabHeight, MeasureSpec.EXACTLY));
+ child.measure(MeasureSpec.makeMeasureSpec(TAB_COUNT * tabWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(tabHeight, MeasureSpec.EXACTLY));
}
+
+ mAllowedVerticalScrollLength = tabHeight - mTabDisplayLabelHeight;
+ setMeasuredDimension(
+ resolveSize(screenWidth, widthMeasureSpec),
+ resolveSize(tabHeight, heightMeasureSpec));
}
private final OnClickListener mAboutTabTouchInterceptListener = new OnClickListener() {
diff --git a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
index 602958d..d668429 100644
--- a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
@@ -19,10 +19,13 @@
import com.android.contacts.ContactLoader;
import com.android.contacts.R;
import com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener;
+import com.android.contacts.util.StreamItemEntry;
import android.app.Fragment;
+import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@@ -54,6 +57,28 @@
*/
private View mTouchInterceptLayer;
+ /**
+ * Listener on clicks on a stream item.
+ * <p>
+ * It assumes the view has a tag of type {@link StreamItemEntry} associated with it.
+ */
+ private View.OnClickListener mStreamItemClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ StreamItemEntry streamItemEntry = (StreamItemEntry) view.getTag();
+ Uri uri;
+ try {
+ uri = Uri.parse(streamItemEntry.getActionUri());
+ } catch (Throwable throwable) {
+ Log.e(TAG, "invalid URI for stream item #" + streamItemEntry.getId() + ": "
+ + streamItemEntry.getActionUri());
+ return;
+ }
+ Intent streamItemIntent = new Intent(streamItemEntry.getAction(), uri);
+ startActivity(streamItemIntent);
+ }
+ };
+
public ContactDetailUpdatesFragment() {
// Explicit constructor for inflation
}
@@ -75,7 +100,7 @@
// have it.
if (mContactData != null) {
ContactDetailDisplayUtils.showSocialStreamItems(inflater, getActivity(), mContactData,
- mStreamContainer);
+ mStreamContainer, mStreamItemClickListener);
}
mAlphaLayer = rootView.findViewById(R.id.alpha_overlay);
@@ -91,7 +116,7 @@
mLookupUri = lookupUri;
mContactData = result;
ContactDetailDisplayUtils.showSocialStreamItems(mInflater, getActivity(), mContactData,
- mStreamContainer);
+ mStreamContainer, mStreamItemClickListener);
}
@Override
diff --git a/src/com/android/contacts/detail/PrimaryActionViewContainer.java b/src/com/android/contacts/detail/PrimaryActionViewContainer.java
new file mode 100644
index 0000000..a342884
--- /dev/null
+++ b/src/com/android/contacts/detail/PrimaryActionViewContainer.java
@@ -0,0 +1,54 @@
+/*
+ * 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.detail;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.widget.AdapterView;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+
+/**
+ * Custom {@link LinearLayout} which remembers its position in the {@link ListView}. Should be
+ * used for primary touch targets in {@link ContactDetailFragment}.
+ */
+/* package */ class PrimaryActionViewContainer extends LinearLayout {
+
+ private ContextMenuInfo mContextMenuInfo;
+
+ public PrimaryActionViewContainer(Context context) {
+ super(context);
+ }
+
+ public PrimaryActionViewContainer(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public PrimaryActionViewContainer(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public void setPosition(int position) {
+ mContextMenuInfo = new AdapterView.AdapterContextMenuInfo(this, position, -1);
+ }
+
+ @Override
+ public ContextMenuInfo getContextMenuInfo() {
+ return mContextMenuInfo;
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/dialpad/DialpadFragment.java b/src/com/android/contacts/dialpad/DialpadFragment.java
index add6b80..a5db5ce 100644
--- a/src/com/android/contacts/dialpad/DialpadFragment.java
+++ b/src/com/android/contacts/dialpad/DialpadFragment.java
@@ -143,9 +143,6 @@
static final String EXTRA_SEND_EMPTY_FLASH
= "com.android.phone.extra.SEND_EMPTY_FLASH";
- /** Indicates if we are opening this dialer to add a call from the InCallScreen. */
- private boolean mIsAddCallMode;
-
private String mCurrentCountryIso;
/**
@@ -313,7 +310,7 @@
mDialpadChooser = (ListView) fragmentView.findViewById(R.id.dialpadChooser);
mDialpadChooser.setOnItemClickListener(this);
- resolveIntent(getActivity().getIntent());
+ configureScreenFromIntent(getActivity().getIntent());
return fragmentView;
}
@@ -323,38 +320,18 @@
}
/**
- * Handles the intent that launched us.
- *
- * We can be launched either with ACTION_DIAL or ACTION_VIEW (which
- * may include a phone number to pre-load), or ACTION_MAIN (which just
- * brings up a blank dialpad).
- *
- * @return true IFF the current intent has the DialtactsActivity.EXTRA_IGNORE_STATE
- * extra set to true, which indicates (to our container) that we should ignore
- * any possible saved state, and instead reset our state based on the parent's
- * intent.
+ * @return true when {@link #mDigits} is actually filled by the Intent.
*/
- public boolean resolveIntent(Intent intent) {
- boolean ignoreState = false;
-
- // by default we are not adding a call.
- mIsAddCallMode = false;
-
- // By default we don't show the "dialpad chooser" UI.
- boolean needToShowDialpadChooser = false;
-
- // Resolve the intent
+ private boolean fillDigitsIfNecessary(Intent intent) {
final String action = intent.getAction();
if (Intent.ACTION_DIAL.equals(action) || Intent.ACTION_VIEW.equals(action)) {
- // see if we are "adding a call" from the InCallScreen; false by default.
- mIsAddCallMode = intent.getBooleanExtra(ADD_CALL_MODE_KEY, false);
-
Uri uri = intent.getData();
if (uri != null) {
if ("tel".equals(uri.getScheme())) {
// Put the requested number into the input area
String data = uri.getSchemeSpecificPart();
setFormattedDigits(data, null);
+ return true;
} else {
String type = intent.getType();
if (People.CONTENT_ITEM_TYPE.equals(type)
@@ -364,22 +341,42 @@
new String[] {PhonesColumns.NUMBER, PhonesColumns.NUMBER_KEY},
null, null, null);
if (c != null) {
- if (c.moveToFirst()) {
- // Put the number into the input area
- setFormattedDigits(c.getString(0), c.getString(1));
+ try {
+ if (c.moveToFirst()) {
+ // Put the number into the input area
+ setFormattedDigits(c.getString(0), c.getString(1));
+ return true;
+ }
+ } finally {
+ c.close();
}
- c.close();
}
}
}
- } else {
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @see #showDialpadChooser(boolean)
+ */
+ private static boolean needToShowDialpadChooser(Intent intent, boolean isAddCallMode) {
+ final String action = intent.getAction();
+
+ boolean needToShowDialpadChooser = false;
+
+ if (Intent.ACTION_DIAL.equals(action) || Intent.ACTION_VIEW.equals(action)) {
+ Uri uri = intent.getData();
+ if (uri == null) {
// ACTION_DIAL or ACTION_VIEW with no data.
// This behaves basically like ACTION_MAIN: If there's
// already an active call, bring up an intermediate UI to
// make the user confirm what they really want to do.
// Be sure *not* to show the dialpad chooser if this is an
// explicit "Add call" action, though.
- if (!mIsAddCallMode && phoneIsInUse()) {
+ if (!isAddCallMode && phoneIsInUse()) {
needToShowDialpadChooser = true;
}
}
@@ -399,11 +396,34 @@
}
}
- // Bring up the "dialpad chooser" IFF we need to make the user
- // confirm which dialpad they really want.
- showDialpadChooser(needToShowDialpadChooser);
+ return needToShowDialpadChooser;
+ }
- return ignoreState;
+ private static boolean isAddCallMode(Intent intent) {
+ final String action = intent.getAction();
+ if (Intent.ACTION_DIAL.equals(action) || Intent.ACTION_VIEW.equals(action)) {
+ // see if we are "adding a call" from the InCallScreen; false by default.
+ return intent.getBooleanExtra(ADD_CALL_MODE_KEY, false);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Checks the given Intent and changes dialpad's UI state. For example, if the Intent requires
+ * the screen to enter "Add Call" mode, this method will show correct UI for the mode.
+ */
+ public void configureScreenFromIntent(Intent intent) {
+ boolean needToShowDialpadChooser = false;
+
+ final boolean isAddCallMode = isAddCallMode(intent);
+ if (!isAddCallMode) {
+ final boolean digitsFilled = fillDigitsIfNecessary(intent);
+ if (!digitsFilled) {
+ needToShowDialpadChooser = needToShowDialpadChooser(intent, isAddCallMode);
+ }
+ }
+ showDialpadChooser(needToShowDialpadChooser);
}
private void setFormattedDigits(String data, String normalizedNumber) {
@@ -476,13 +496,10 @@
}
Activity parent = getActivity();
- // See if we were invoked with a DIAL intent. If we were, fill in the appropriate
- // digits in the dialer field.
if (parent instanceof DialtactsActivity) {
- Uri dialUri = ((DialtactsActivity) parent).getAndClearDialUri();
- if (dialUri != null) {
- resolveIntent(parent.getIntent());
- }
+ // See if we were invoked with a DIAL intent. If we were, fill in the appropriate
+ // digits in the dialer field.
+ fillDigitsIfNecessary(parent.getIntent());
}
// While we're in the foreground, listen for phone state changes,
@@ -904,8 +921,8 @@
// ListView. We do this only once.
if (mDialpadChooserAdapter == null) {
mDialpadChooserAdapter = new DialpadChooserAdapter(getActivity());
- mDialpadChooser.setAdapter(mDialpadChooserAdapter);
}
+ mDialpadChooser.setAdapter(mDialpadChooserAdapter);
} else {
// Log.i(TAG, "Displaying normal Dialer UI.");
mDigits.setVisibility(View.VISIBLE);
diff --git a/src/com/android/contacts/group/GroupBrowseListAdapter.java b/src/com/android/contacts/group/GroupBrowseListAdapter.java
index 753261a..630a397 100644
--- a/src/com/android/contacts/group/GroupBrowseListAdapter.java
+++ b/src/com/android/contacts/group/GroupBrowseListAdapter.java
@@ -56,6 +56,15 @@
public void setCursor(Cursor cursor) {
mCursor = cursor;
+
+ // If there's no selected group already and the cursor is valid, then by default, select the
+ // first group
+ if (mSelectedGroupUri == null && cursor != null && cursor.getCount() > 0) {
+ GroupListItem firstItem = getItem(0);
+ long groupId = (firstItem == null) ? null : firstItem.getGroupId();
+ mSelectedGroupUri = getGroupUriFromId(groupId);
+ }
+
notifyDataSetChanged();
}
@@ -89,6 +98,10 @@
return mSelectedGroupUri != null && mSelectedGroupUri.equals(groupUri);
}
+ public Uri getSelectedGroup() {
+ return mSelectedGroupUri;
+ }
+
@Override
public int getCount() {
return mCursor == null ? 0 : mCursor.getCount();
diff --git a/src/com/android/contacts/group/GroupBrowseListFragment.java b/src/com/android/contacts/group/GroupBrowseListFragment.java
index a1544cf..835400f 100644
--- a/src/com/android/contacts/group/GroupBrowseListFragment.java
+++ b/src/com/android/contacts/group/GroupBrowseListFragment.java
@@ -223,6 +223,7 @@
}
mListView.setEmptyView(mEmptyView);
+ mSelectedGroupUri = mAdapter.getSelectedGroup();
if (mSelectionVisible && mSelectedGroupUri != null) {
viewGroup(mSelectedGroupUri);
}
diff --git a/src/com/android/contacts/group/GroupEditorFragment.java b/src/com/android/contacts/group/GroupEditorFragment.java
index 9a09c77..ccc84a2 100644
--- a/src/com/android/contacts/group/GroupEditorFragment.java
+++ b/src/com/android/contacts/group/GroupEditorFragment.java
@@ -329,6 +329,7 @@
mAutoCompleteAdapter.setContentResolver(mContentResolver);
mAutoCompleteAdapter.setAccountType(mAccountType);
mAutoCompleteAdapter.setAccountName(mAccountName);
+ mAutoCompleteAdapter.setDataSet(mDataSet);
mAutoCompleteTextView.setAdapter(mAutoCompleteAdapter);
mAutoCompleteTextView.setOnItemClickListener(new OnItemClickListener() {
@Override
@@ -561,11 +562,12 @@
}
private boolean hasValidGroupName() {
- return !TextUtils.isEmpty(mGroupNameView.getText());
+ return mGroupNameView != null && !TextUtils.isEmpty(mGroupNameView.getText());
}
private boolean hasNameChange() {
- return !mGroupNameView.getText().toString().equals(mOriginalGroupName);
+ return mGroupNameView != null &&
+ !mGroupNameView.getText().toString().equals(mOriginalGroupName);
}
private boolean hasMembershipChange() {
diff --git a/src/com/android/contacts/group/SuggestedMemberListAdapter.java b/src/com/android/contacts/group/SuggestedMemberListAdapter.java
index 4f4413c..653cc25 100644
--- a/src/com/android/contacts/group/SuggestedMemberListAdapter.java
+++ b/src/com/android/contacts/group/SuggestedMemberListAdapter.java
@@ -76,9 +76,9 @@
private ContentResolver mContentResolver;
private LayoutInflater mInflater;
- private String mAccountType = "";
- private String mAccountName = "";
- private String mDataSet = "";
+ private String mAccountType;
+ private String mAccountName;
+ private String mDataSet;
// TODO: Make this a Map for better performance when we check if a new contact is in the list
// or not
@@ -355,5 +355,10 @@
public void setPhotoByteArray(byte[] photo) {
mPhoto = photo;
}
+
+ @Override
+ public String toString() {
+ return getDisplayName();
+ }
}
}
diff --git a/src/com/android/contacts/list/ContactListAdapter.java b/src/com/android/contacts/list/ContactListAdapter.java
index 7322fc6..467dcc3 100644
--- a/src/com/android/contacts/list/ContactListAdapter.java
+++ b/src/com/android/contacts/list/ContactListAdapter.java
@@ -15,6 +15,8 @@
*/
package com.android.contacts.list;
+import com.android.contacts.R;
+
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
@@ -28,7 +30,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
-import android.widget.QuickContactBadge;
/**
* A cursor adapter for the {@link ContactsContract.Contacts#CONTENT_TYPE} content type.
@@ -121,7 +122,7 @@
public ContactListAdapter(Context context) {
super(context);
- mUnknownNameText = context.getText(android.R.string.unknownName);
+ mUnknownNameText = context.getText(R.string.missing_name);
mViewTypeProfileEntry = getViewTypeCount() - 1;
}
diff --git a/src/com/android/contacts/list/ContactTileAdapter.java b/src/com/android/contacts/list/ContactTileAdapter.java
index 8993cdd..2c64d8f 100644
--- a/src/com/android/contacts/list/ContactTileAdapter.java
+++ b/src/com/android/contacts/list/ContactTileAdapter.java
@@ -19,19 +19,16 @@
import com.android.contacts.ContactTileLoaderFactory;
import com.android.contacts.GroupMemberLoader;
import com.android.contacts.R;
-import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.DataKind;
+import com.android.contacts.list.ContactTileAdapter.DisplayType;
import android.content.ContentUris;
import android.content.Context;
+import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts;
import android.view.View;
-import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
@@ -50,6 +47,7 @@
private DisplayType mDisplayType;
private Listener mListener;
private Context mContext;
+ private Resources mResources;
private Cursor mContactCursor = null;
private ContactPhotoManager mPhotoManager;
@@ -114,6 +112,7 @@
DisplayType displayType) {
mListener = listener;
mContext = context;
+ mResources = context.getResources();
mColumnCount = (displayType == DisplayType.FREQUENT_ONLY ? 1 : numCols);
mDisplayType = displayType;
@@ -213,7 +212,8 @@
String lookupKey = cursor.getString(mLookupIndex);
ContactEntry contact = new ContactEntry();
- contact.name = cursor.getString(mNameIndex);
+ String name = cursor.getString(mNameIndex);
+ contact.name = (name != null) ? name : mResources.getString(R.string.missing_name);
contact.status = cursor.getString(mStatusIndex);
contact.photoUri = (photoUri != null ? Uri.parse(photoUri) : null);
contact.lookupKey = ContentUris.withAppendedId(
@@ -223,8 +223,8 @@
if (mDisplayType == DisplayType.STREQUENT_PHONE_ONLY) {
int phoneNumberType = cursor.getInt(mPhoneNumberTypeIndex);
String phoneNumberCustomLabel = cursor.getString(mPhoneNumberLabelIndex);
- contact.phoneLabel = (String) Phone.getTypeLabel(mContext.getResources(),
- phoneNumberType, phoneNumberCustomLabel);
+ contact.phoneLabel = (String) Phone.getTypeLabel(mResources, phoneNumberType,
+ phoneNumberCustomLabel);
contact.phoneNumber = cursor.getString(mPhoneNumberIndex);
} else {
contact.status = cursor.getString(mStatusIndex);
@@ -426,10 +426,19 @@
}
}
+ private ContactTileView.Listener mContactTileListener = new ContactTileView.Listener() {
+ @Override
+ public void onClick(ContactTileView contactTileView) {
+ if (mListener != null) {
+ mListener.onContactSelected(contactTileView.getLookupUri());
+ }
+ }
+ };
+
/**
* Acts as a row item composed of {@link ContactTileView}
*/
- private class ContactTileRow extends LinearLayout implements OnClickListener {
+ private class ContactTileRow extends LinearLayout {
private int mItemViewType;
private int mLayoutResId;
@@ -454,7 +463,7 @@
}
private void addTileFromEntry(ContactEntry entry, int tileIndex) {
- ContactTileView contactTile = null;
+ final ContactTileView contactTile;
if (getChildCount() <= tileIndex) {
switch (mItemViewType) {
@@ -476,7 +485,7 @@
contactTile.setLayoutParams(new LinearLayout.LayoutParams(0,
LinearLayout.LayoutParams.WRAP_CONTENT, 1.0f));
contactTile.setPhotoManager(mPhotoManager);
- contactTile.setOnClickListener(this);
+ contactTile.setListener(mContactTileListener);
addView(contactTile);
} else {
contactTile = (ContactTileView) getChildAt(tileIndex);
@@ -484,11 +493,6 @@
contactTile.setClickable(entry != null);
contactTile.loadFromContact(entry);
}
-
- @Override
- public void onClick(View v) {
- mListener.onContactSelected(((ContactTileView) v).getLookupUri());
- }
}
/**
diff --git a/src/com/android/contacts/list/ContactTileSecondaryTargetView.java b/src/com/android/contacts/list/ContactTileSecondaryTargetView.java
index 862e23d..073ac29 100644
--- a/src/com/android/contacts/list/ContactTileSecondaryTargetView.java
+++ b/src/com/android/contacts/list/ContactTileSecondaryTargetView.java
@@ -20,9 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.util.AttributeSet;
-import android.view.MotionEvent;
import android.view.View;
-import android.view.View.OnClickListener;
import android.widget.ImageButton;
/**
@@ -30,8 +28,7 @@
* in a perfect square like the {@link ContactTileStarredView}. However it adds in an additional
* touch target for a secondary action.
*/
-public class ContactTileSecondaryTargetView extends ContactTileStarredView
- implements OnClickListener {
+public class ContactTileSecondaryTargetView extends ContactTileStarredView {
private final static String TAG = ContactTileSecondaryTargetView.class.getSimpleName();
@@ -44,12 +41,13 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mSecondaryButton = (ImageButton) findViewById(R.id.contact_tile_secondary_button);
- mSecondaryButton.setOnClickListener(this);
- }
- @Override
- public void onClick(View v) {
- getContext().startActivity(new Intent(Intent.ACTION_VIEW, getLookupUri()));
+ mSecondaryButton = (ImageButton) findViewById(R.id.contact_tile_secondary_button);
+ mSecondaryButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ getContext().startActivity(new Intent(Intent.ACTION_VIEW, getLookupUri()));
+ }
+ });
}
}
diff --git a/src/com/android/contacts/list/ContactTileView.java b/src/com/android/contacts/list/ContactTileView.java
index 3839573..aee34c9 100644
--- a/src/com/android/contacts/list/ContactTileView.java
+++ b/src/com/android/contacts/list/ContactTileView.java
@@ -27,6 +27,7 @@
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;
+import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.QuickContactBadge;
import android.widget.TextView;
@@ -46,6 +47,8 @@
private TextView mPhoneLabel;
private TextView mPhoneNumber;
private ContactPhotoManager mPhotoManager = null;
+ private ImageButton mPushState;
+ private Listener mListener;
public ContactTileView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -63,6 +66,22 @@
mStatus = (TextView) findViewById(R.id.contact_tile_status);
mPhoneLabel = (TextView) findViewById(R.id.contact_tile_phone_type);
mPhoneNumber = (TextView) findViewById(R.id.contact_tile_phone_number);
+ mPushState = (ImageButton) findViewById(R.id.contact_tile_push_state);
+
+ OnClickListener listener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mListener != null) {
+ mListener.onClick(ContactTileView.this);
+ }
+ }
+ };
+
+ if(mPushState != null) {
+ mPushState.setOnClickListener(listener);
+ } else {
+ setOnClickListener(listener);
+ }
}
public void setPhotoManager(ContactPhotoManager photoManager) {
@@ -130,7 +149,15 @@
}
}
+ public void setListener(Listener listener) {
+ mListener = listener;
+ }
+
public Uri getLookupUri() {
return mLookupUri;
}
+
+ public interface Listener {
+ void onClick(ContactTileView contactTileView);
+ }
}
diff --git a/src/com/android/contacts/quickcontact/FloatingChildLayout.java b/src/com/android/contacts/quickcontact/FloatingChildLayout.java
index 11d3176..62b4f1a 100644
--- a/src/com/android/contacts/quickcontact/FloatingChildLayout.java
+++ b/src/com/android/contacts/quickcontact/FloatingChildLayout.java
@@ -114,8 +114,8 @@
} else {
// default is centered horizontally around target...
final int childLeft = target.centerX() - (childWidth / 2);
- // ... and vertically aligned at the top
- final int childTop = target.top;
+ // ... and vertically aligned a bit below centered
+ final int childTop = target.centerY() - Math.round(childHeight * 0.35f);
// when child is outside bounds, nudge back inside
final int clampedChildLeft = clampDimension(childLeft, childWidth, getWidth());
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index 47e7173..1ef40db 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -68,6 +68,7 @@
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
+import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.ImageButton;
import android.widget.ImageView;
@@ -163,6 +164,10 @@
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
+ // Show QuickContact in front of soft input
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+ WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
+
setContentView(R.layout.quickcontact_activity);
mFloatingLayout = (FloatingChildLayout) findViewById(R.id.floating_layout);
@@ -228,7 +233,7 @@
// find and prepare correct header view
mPhotoContainer = findViewById(R.id.photo_container);
- setHeaderText(R.id.name, R.string.quickcontact_missing_name);
+ setHeaderNameText(R.id.name, R.string.missing_name);
setHeaderText(R.id.status, null);
setHeaderText(R.id.timestamp, null);
setHeaderImage(R.id.presence, null);
@@ -317,12 +322,33 @@
}
};
- /** Assign this string to the view, if found in {@link #mPhotoContainer}. */
+ /** Assign this string to the view if it is not empty. */
+ private void setHeaderNameText(int id, int resId) {
+ setHeaderNameText(id, getText(resId));
+ }
+
+ /** Assign this string to the view if it is not empty. */
+ private void setHeaderNameText(int id, CharSequence value) {
+ final View view = mPhotoContainer.findViewById(id);
+ if (view instanceof TextView) {
+ if (!TextUtils.isEmpty(value)) {
+ ((TextView)view).setText(value);
+ }
+ }
+ }
+
+ /**
+ * Assign this string to the view (if found in {@link #mPhotoContainer}), or hiding this view
+ * if there is no string.
+ */
private void setHeaderText(int id, int resId) {
setHeaderText(id, getText(resId));
}
- /** Assign this string to the view, if found in {@link #mPhotoContainer}. */
+ /**
+ * Assign this string to the view (if found in {@link #mPhotoContainer}), or hiding this view
+ * if there is no string.
+ */
private void setHeaderText(int id, CharSequence value) {
final View view = mPhotoContainer.findViewById(id);
if (view instanceof TextView) {
@@ -483,7 +509,7 @@
final Drawable statusIcon = ContactPresenceIconUtil.getChatCapabilityIcon(
context, presence, chatCapability);
- setHeaderText(R.id.name, name);
+ setHeaderNameText(R.id.name, name);
// TODO: Bring this back once we have a design
// setHeaderImage(R.id.presence, statusIcon);
}
diff --git a/src/com/android/contacts/quickcontact/QuickContactListFragment.java b/src/com/android/contacts/quickcontact/QuickContactListFragment.java
index 910fede..1c36ae1 100644
--- a/src/com/android/contacts/quickcontact/QuickContactListFragment.java
+++ b/src/com/android/contacts/quickcontact/QuickContactListFragment.java
@@ -50,7 +50,8 @@
mFragmentContainer = (LinearLayout) inflater.inflate(R.layout.quickcontact_list_fragment,
container, false);
mListView = (ListView) mFragmentContainer.findViewById(R.id.list);
- mListView.setOnItemClickListener(mItemClickListener);
+ mListView.setItemsCanFocus(true);
+
mFragmentContainer.setOnClickListener(mOutsideClickListener);
configureAdapter();
return mFragmentContainer;
@@ -98,10 +99,14 @@
android.R.id.text1);
final TextView text2 = (TextView) resultView.findViewById(
android.R.id.text2);
+ final View primaryActionContainer = resultView.findViewById(
+ R.id.primary_action_view_container);
final ImageView alternateActionButton = (ImageView) resultView.findViewById(
R.id.secondary_action_button);
final View alternateActionDivider = resultView.findViewById(R.id.vertical_divider);
+ primaryActionContainer.setOnClickListener(mPrimaryActionClickListener);
+ primaryActionContainer.setTag(action);
alternateActionButton.setOnClickListener(mSecondaryActionClickListener);
alternateActionButton.setTag(action);
@@ -110,14 +115,22 @@
alternateActionButton.setImageDrawable(action.getAlternateIcon());
text1.setText(action.getBody());
- text2.setText(action.getSubtitle().toString().toUpperCase());
+ text2.setText(action.getSubtitle());
- resultView.setTag(action);
return resultView;
}
});
}
+ /** A data item (e.g. phone number) was clicked */
+ protected final OnClickListener mPrimaryActionClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ final Action action = (Action) v.getTag();
+ if (mListener != null) mListener.onItemClicked(action, false);
+ }
+ };
+
/** A secondary action (SMS) was clicked */
protected final OnClickListener mSecondaryActionClickListener = new OnClickListener() {
@Override
@@ -127,16 +140,6 @@
}
};
- /** A data item (e.g. phone number) was clicked */
- private final AbsListView.OnItemClickListener mItemClickListener =
- new AbsListView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- final Action action = (Action) view.getTag();
- if (mListener != null) mListener.onItemClicked(action, false);
- }
- };
-
private final OnClickListener mOutsideClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
diff --git a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
index 3d7881b..4686c81 100644
--- a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
+++ b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
@@ -186,6 +186,10 @@
SpannableStringBuilder sb = new SpannableStringBuilder();
CharSequence name = displayName;
+ // If there is no display name, use the default missing name string
+ if (TextUtils.isEmpty(name)) {
+ name = context.getString(R.string.missing_name);
+ }
if (!TextUtils.isEmpty(phoneticName)) {
name = context.getString(R.string.widget_name_and_phonetic,
name, phoneticName);
diff --git a/src/com/android/contacts/widget/ProportionalLayout.java b/src/com/android/contacts/widget/ProportionalLayout.java
new file mode 100644
index 0000000..52a67d4
--- /dev/null
+++ b/src/com/android/contacts/widget/ProportionalLayout.java
@@ -0,0 +1,146 @@
+/*
+ * 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.widget;
+
+import com.android.contacts.R;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Layout that calculates its height based on its width, or vice versa (depending on the set
+ * {@link #setDirection(Direction)}. The factor is specified in {@link #setRatio(float)}.
+ * <p>For {@link Direction#heightToWidth}: width := height * factor</p>
+ * <p>For {@link Direction#widthToHeight}: height := width * factor</p>
+ * <p>Only one child is allowed; if more are required, another ViewGroup can be used as the direct
+ * child of this layout.</p>
+ */
+public class ProportionalLayout extends ViewGroup {
+ /** Specifies whether the width should be calculated based on the height or vice-versa */
+ public enum Direction {
+ widthToHeight("widthToHeight"),
+ heightToWidth("heightToWidth");
+
+ public final String XmlName;
+
+ private Direction(String xmlName) {
+ XmlName = xmlName;
+ }
+
+ /**
+ * Parses the given direction string and returns the Direction instance. This
+ * should be used when inflating from xml
+ */
+ public static Direction parse(String value) {
+ if (widthToHeight.XmlName.equals(value)) {
+ return Direction.widthToHeight;
+ } else if (heightToWidth.XmlName.equals(value)) {
+ return Direction.heightToWidth;
+ } else {
+ throw new IllegalStateException("direction must be either " +
+ widthToHeight.XmlName + " or " + heightToWidth.XmlName);
+ }
+ }
+ }
+
+ private Direction mDirection;
+ private float mRatio;
+
+ public ProportionalLayout(Context context) {
+ super(context);
+ }
+
+ public ProportionalLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initFromAttributes(context, attrs);
+ }
+
+ public ProportionalLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ initFromAttributes(context, attrs);
+ }
+
+ private void initFromAttributes(Context context, AttributeSet attrs) {
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ProportionalLayout);
+
+ mDirection = Direction.parse(a.getString(R.styleable.ProportionalLayout_direction));
+ mRatio = a.getFloat(R.styleable.ProportionalLayout_ratio, 1.0f);
+
+ a.recycle();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (getChildCount() != 1) {
+ throw new IllegalStateException("ProportionalLayout requires exactly one child");
+ }
+
+ final View child = getChildAt(0);
+
+ // Do a first pass to get the optimal size
+ measureChild(child, widthMeasureSpec, heightMeasureSpec);
+ final int childWidth = child.getMeasuredWidth();
+ final int childHeight = child.getMeasuredHeight();
+
+ final int width;
+ final int height;
+ if (mDirection == Direction.heightToWidth) {
+ width = Math.round(childHeight * mRatio);
+ height = childHeight;
+ } else {
+ width = childWidth;
+ height = Math.round(childWidth * mRatio);
+ }
+
+ // Do a second pass so that all children are informed of the new size
+ measureChild(child,
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+
+ setMeasuredDimension(
+ resolveSize(width, widthMeasureSpec), resolveSize(height, heightMeasureSpec));
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (getChildCount() != 1) {
+ throw new IllegalStateException("ProportionalLayout requires exactly one child");
+ }
+
+ final View child = getChildAt(0);
+ child.layout(0, 0, right-left, bottom-top);
+ }
+
+ public Direction getDirection() {
+ return mDirection;
+ }
+
+ public void setDirection(Direction direction) {
+ mDirection = direction;
+ }
+
+ public float getRatio() {
+ return mRatio;
+ }
+
+ public void setRatio(float ratio) {
+ mRatio = ratio;
+ }
+}
diff --git a/tests/res/values/donottranslate_strings.xml b/tests/res/values/donottranslate_strings.xml
index 528b129..194b6ca 100644
--- a/tests/res/values/donottranslate_strings.xml
+++ b/tests/res/values/donottranslate_strings.xml
@@ -107,4 +107,9 @@
<item>Two short sections with headers</item>
<item>Five short sections with headers</item>
</string-array>
+
+ <string name="attribution_google_plus">Google+</string>
+ <string name="attribution_google_talk">Google Talk</string>
+ <string name="attribution_flicker">Flicker</string>
+ <string name="attribution_twitter">Twitter</string>
</resources>
diff --git a/tests/src/com/android/contacts/detail/ContactDetailDisplayUtilsTest.java b/tests/src/com/android/contacts/detail/ContactDetailDisplayUtilsTest.java
new file mode 100644
index 0000000..98001ae
--- /dev/null
+++ b/tests/src/com/android/contacts/detail/ContactDetailDisplayUtilsTest.java
@@ -0,0 +1,259 @@
+/*
+ * 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.detail;
+
+import com.android.contacts.R;
+import com.android.contacts.util.StreamItemEntry;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.Html;
+import android.text.Spanned;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * Unit tests for {@link ContactDetailDisplayUtils}.
+ */
+@SmallTest
+public class ContactDetailDisplayUtilsTest extends AndroidTestCase {
+ private static final String TEST_STREAM_ITEM_TEXT = "text";
+
+ private LinearLayout mParent;
+ private LayoutInflater mLayoutInflater;
+ private FakeOnClickListener mListener = new FakeOnClickListener();
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mParent = new LinearLayout(getContext());
+ mLayoutInflater =
+ (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testAddStreamItemText_IncludesComments() {
+ StreamItemEntry streamItem = getTestBuilder().setComment("1 comment").build();
+ View streamItemView = addStreamItemText(streamItem);
+ assertHasText(streamItemView, R.id.stream_item_comments, "1 comment");
+ }
+
+ public void testAddStreamItemText_IncludesHtmlComments() {
+ StreamItemEntry streamItem = getTestBuilder().setComment("1 <b>comment</b>").build();
+ View streamItemView = addStreamItemText(streamItem);
+ assertHasHtmlText(streamItemView, R.id.stream_item_comments, "1 <b>comment<b>");
+ }
+
+ public void testAddStreamItemText_NoComments() {
+ StreamItemEntry streamItem = getTestBuilder().setComment(null).build();
+ View streamItemView = addStreamItemText(streamItem);
+ assertGone(streamItemView, R.id.stream_item_comments);
+ }
+
+ public void testAddStreamItemToContainer_NoAction() {
+ StreamItemEntry streamItem = getTestBuilder()
+ .setAction(null)
+ .setActionUri(null)
+ .build();
+ addStreamItemToContainer(streamItem, mListener);
+ assertStreamItemNotClickable();
+ }
+
+ public void testAddStreamItemToContainer_WithActionButNoActionUri() {
+ StreamItemEntry streamItem = getTestBuilder()
+ .setAction("action")
+ .setActionUri(null)
+ .build();
+ addStreamItemToContainer(streamItem, mListener);
+ assertStreamItemNotClickable();
+ }
+
+ public void testAddStreamItemToContainer_WithActionUriButNoAction() {
+ StreamItemEntry streamItem = getTestBuilder()
+ .setAction(null)
+ .setActionUri("http://www.google.com")
+ .build();
+ addStreamItemToContainer(streamItem, mListener);
+ assertStreamItemNotClickable();
+ }
+
+ public void testAddStreamItemToContainer_WithActionAndActionUri() {
+ StreamItemEntry streamItem = getTestBuilder()
+ .setAction("action")
+ .setActionUri("http://www.google.com")
+ .build();
+ addStreamItemToContainer(streamItem, mListener);
+ assertStreamItemClickable();
+ assertStreamItemHasOnClickListener();
+ assertStreamItemHasTag(streamItem);
+ }
+
+ /** Checks that the stream item view is clickable. */
+ private void assertStreamItemClickable() {
+ View streamItemView = mParent.findViewById(R.id.stream_item_content);
+ assertNotNull("should have a stream item", streamItemView);
+ assertTrue("should be clickable", streamItemView.isClickable());
+ assertTrue("should be focusable", streamItemView.isFocusable());
+ }
+
+ /** Asserts that there is a stream item but it is not clickable. */
+ private void assertStreamItemNotClickable() {
+ View streamItemView = mParent.findViewById(R.id.stream_item_content);
+ assertNotNull("should have a stream item", streamItemView);
+ assertFalse("should not be clickable", streamItemView.isClickable());
+ assertFalse("should not be focusable", streamItemView.isFocusable());
+ }
+
+ /** Checks that the stream item view has a click listener. */
+ private void assertStreamItemHasOnClickListener() {
+ // Check that the on-click listener is invoked when clicked.
+ View streamItemView = mParent.findViewById(R.id.stream_item_content);
+ assertFalse("listener should have not been invoked yet", mListener.clicked);
+ streamItemView.performClick();
+ assertTrue("listener should have been invoked", mListener.clicked);
+ }
+
+ /** Checks that the stream item view has the given stream item as its tag. */
+ private void assertStreamItemHasTag(StreamItemEntry streamItem) {
+ // The view's tag should point to the stream item entry for this view.
+ View streamItemView = mParent.findViewById(R.id.stream_item_content);
+ Object tag = streamItemView.getTag();
+ assertNotNull("should have a tag", tag);
+ assertTrue("should be a StreamItemEntry", tag instanceof StreamItemEntry);
+ StreamItemEntry streamItemTag = (StreamItemEntry) tag;
+ // The streamItem itself should be in the tag.
+ assertSame(streamItem, streamItemTag);
+ }
+
+ /** Checks that the given id corresponds to a visible text view with the expected text. */
+ private void assertHasText(View parent, int textViewId, String expectedText) {
+ TextView textView = (TextView) parent.findViewById(textViewId);
+ assertNotNull(textView);
+ assertEquals(View.VISIBLE, textView.getVisibility());
+ assertEquals(expectedText, textView.getText().toString());
+ }
+
+ /** Checks that the given id corresponds to a visible text view with the expected HTML. */
+ private void assertHasHtmlText(View parent, int textViewId, String expectedHtml) {
+ TextView textView = (TextView) parent.findViewById(textViewId);
+ assertNotNull(textView);
+ assertEquals(View.VISIBLE, textView.getVisibility());
+ assertSpannableEquals(Html.fromHtml(expectedHtml), textView.getText());
+ }
+
+ /**
+ * Asserts that a char sequence is actually a {@link Spanned} matching the one expected.
+ */
+ private void assertSpannableEquals(Spanned expected, CharSequence actualCharSequence) {
+ assertEquals(expected.toString(), actualCharSequence.toString());
+ assertTrue("char sequence should be an instance of Spanned",
+ actualCharSequence instanceof Spanned);
+ Spanned actual = (Spanned) actualCharSequence;
+ assertEquals(Html.toHtml(expected), Html.toHtml(actual));
+ }
+
+ /** Checks that the given id corresponds to a gone view. */
+ private void assertGone(View parent, int textId) {
+ View view = parent.findViewById(textId);
+ assertNotNull(view);
+ assertEquals(View.GONE, view.getVisibility());
+ }
+
+ /**
+ * Calls {@link ContactDetailDisplayUtils#addStreamItemText(LayoutInflater, Context,
+ * StreamItemEntry, ViewGroup)} with the default parameters and the given stream item.
+ */
+ private View addStreamItemText(StreamItemEntry streamItem) {
+ return ContactDetailDisplayUtils.addStreamItemText(
+ mLayoutInflater, getContext(), streamItem, mParent);
+ }
+
+ /**
+ * Calls {@link ContactDetailDisplayUtils#addStreamItemToContainer(LayoutInflater,
+ * Context,StreamItemEntry, LinearLayout, android.view.View.OnClickListener)} with the default
+ * parameters and the given stream item and listener.
+ */
+ private void addStreamItemToContainer(StreamItemEntry streamItem,
+ View.OnClickListener listener) {
+ ContactDetailDisplayUtils.addStreamItemToContainer(mLayoutInflater, getContext(),
+ streamItem, mParent, listener);
+ }
+
+ /**
+ * Simple fake implementation of {@link View.OnClickListener} which sets a member variable to
+ * true when clicked.
+ */
+ private final class FakeOnClickListener implements View.OnClickListener {
+ public boolean clicked = false;
+
+ @Override
+ public void onClick(View view) {
+ clicked = true;
+ }
+ }
+
+ private static class StreamItemEntryBuilder {
+ private long mId;
+ private String mText;
+ private String mComment;
+ private long mTimestamp;
+ private String mAction;
+ private String mActionUri;
+ private String mResPackage;
+ private int mIconRes;
+ private int mLabelRes;
+
+ public StreamItemEntryBuilder() {}
+
+ public StreamItemEntryBuilder setText(String text) {
+ mText = text;
+ return this;
+ }
+
+ public StreamItemEntryBuilder setComment(String comment) {
+ mComment = comment;
+ return this;
+ }
+
+ public StreamItemEntryBuilder setAction(String action) {
+ mAction = action;
+ return this;
+ }
+
+ public StreamItemEntryBuilder setActionUri(String actionUri) {
+ mActionUri = actionUri;
+ return this;
+ }
+
+ public StreamItemEntry build() {
+ return new StreamItemEntry(mId, mText, mComment, mTimestamp, mAction, mActionUri,
+ mResPackage, mIconRes, mLabelRes);
+ }
+ }
+
+ private StreamItemEntryBuilder getTestBuilder() {
+ return new StreamItemEntryBuilder().setText(TEST_STREAM_ITEM_TEXT);
+ }
+}
diff --git a/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java b/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
index 67bf725..a6222db 100644
--- a/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
+++ b/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
@@ -105,26 +105,26 @@
}
public void testSingleWritableRawContact() {
- expectQuery().returnRow(1, WRITABLE_ACCOUNT_TYPE, 13, "foo");
+ expectQuery().returnRow(1, WRITABLE_ACCOUNT_TYPE, null, 13, "foo");
assertWithMessageId(R.string.deleteConfirmation);
}
public void testReadOnlyRawContacts() {
- expectQuery().returnRow(1, READONLY_ACCOUNT_TYPE, 13, "foo");
+ expectQuery().returnRow(1, READONLY_ACCOUNT_TYPE, null, 13, "foo");
assertWithMessageId(R.string.readOnlyContactWarning);
}
public void testMixOfWritableAndReadOnlyRawContacts() {
expectQuery()
- .returnRow(1, WRITABLE_ACCOUNT_TYPE, 13, "foo")
- .returnRow(2, READONLY_ACCOUNT_TYPE, 13, "foo");
+ .returnRow(1, WRITABLE_ACCOUNT_TYPE, null, 13, "foo")
+ .returnRow(2, READONLY_ACCOUNT_TYPE, null, 13, "foo");
assertWithMessageId(R.string.readOnlyContactDeleteConfirmation);
}
public void testMultipleWritableRawContacts() {
expectQuery()
- .returnRow(1, WRITABLE_ACCOUNT_TYPE, 13, "foo")
- .returnRow(2, WRITABLE_ACCOUNT_TYPE, 13, "foo");
+ .returnRow(1, WRITABLE_ACCOUNT_TYPE, null, 13, "foo")
+ .returnRow(2, WRITABLE_ACCOUNT_TYPE, null, 13, "foo");
assertWithMessageId(R.string.multipleContactDeleteConfirmation);
}
diff --git a/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java b/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java
index d70cb44..e0b443a 100644
--- a/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java
+++ b/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java
@@ -89,7 +89,7 @@
public void testSendSmsWhenOnlyOneNumberAvailable() {
Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 13);
expectQuery(contactUri)
- .returnRow(1, "123", 0, null, Phone.TYPE_HOME, null);
+ .returnRow(1, "123", 0, null, null, Phone.TYPE_HOME, null);
TestPhoneNumberInteraction interaction = new TestPhoneNumberInteraction(
mContext, InteractionType.SMS, null);
@@ -107,7 +107,7 @@
public void testSendSmsWhenDataIdIsProvided() {
Uri dataUri = ContentUris.withAppendedId(Data.CONTENT_URI, 1);
expectQuery(dataUri, true /* isDataUri */ )
- .returnRow(1, "987", 0, null, Phone.TYPE_HOME, null);
+ .returnRow(1, "987", 0, null, null, Phone.TYPE_HOME, null);
TestPhoneNumberInteraction interaction = new TestPhoneNumberInteraction(
mContext, InteractionType.SMS, null);
@@ -125,8 +125,8 @@
public void testSendSmsWhenThereIsPrimaryNumber() {
Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 13);
expectQuery(contactUri)
- .returnRow(1, "123", 0, null, Phone.TYPE_HOME, null)
- .returnRow(2, "456", 1, null, Phone.TYPE_HOME, null);
+ .returnRow(1, "123", 0, null, null, Phone.TYPE_HOME, null)
+ .returnRow(2, "456", 1, null, null, Phone.TYPE_HOME, null);
TestPhoneNumberInteraction interaction = new TestPhoneNumberInteraction(
mContext, InteractionType.SMS, null);
@@ -164,8 +164,8 @@
public void testCallNumberWhenThereAreDuplicates() {
Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 13);
expectQuery(contactUri)
- .returnRow(1, "123", 0, null, Phone.TYPE_HOME, null)
- .returnRow(2, "123", 0, null, Phone.TYPE_WORK, null);
+ .returnRow(1, "123", 0, null, null, Phone.TYPE_HOME, null)
+ .returnRow(2, "123", 0, null, null, Phone.TYPE_WORK, null);
TestPhoneNumberInteraction interaction = new TestPhoneNumberInteraction(
mContext, InteractionType.PHONE_CALL, null);
@@ -183,8 +183,8 @@
public void testShowDisambigDialogForCalling() {
Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 13);
expectQuery(contactUri)
- .returnRow(1, "123", 0, "account", Phone.TYPE_HOME, "label")
- .returnRow(2, "456", 0, null, Phone.TYPE_WORK, null);
+ .returnRow(1, "123", 0, "account", null, Phone.TYPE_HOME, "label")
+ .returnRow(2, "456", 0, null, null, Phone.TYPE_WORK, null);
TestPhoneNumberInteraction interaction = new TestPhoneNumberInteraction(
mContext, InteractionType.PHONE_CALL, null);
diff --git a/tests/src/com/android/contacts/tests/streamitems/StreamItemPopulatorActivity.java b/tests/src/com/android/contacts/tests/streamitems/StreamItemPopulatorActivity.java
index c984418..e27c767 100644
--- a/tests/src/com/android/contacts/tests/streamitems/StreamItemPopulatorActivity.java
+++ b/tests/src/com/android/contacts/tests/streamitems/StreamItemPopulatorActivity.java
@@ -83,6 +83,17 @@
"<i>24567</i> <font color='blue' size='+1'><b>likes</b></font>"
};
+ private Integer[] labelIds = new Integer[] {
+ R.string.attribution_google_plus,
+ R.string.attribution_google_talk,
+ R.string.attribution_flicker,
+ R.string.attribution_twitter
+ };
+
+ public Integer[] iconIds = new Integer[] {
+ R.drawable.default_icon,
+ };
+
// Photos to randomly select from.
private Integer[] imageIds = new Integer[]{
R.drawable.android,
@@ -242,6 +253,7 @@
}
private ContentValues buildStreamItemValues(String accountType, String accountName) {
+ boolean includeAttribution = randInt(100) < 70;
boolean includeComments = randInt(100) < 30;
boolean includeAction = randInt(100) < 30;
ContentValues values = new ContentValues();
@@ -250,6 +262,14 @@
String.format(pickRandom(snippetStrings) , place)
+ (includeComments ? " [c]" : "")
+ (includeAction ? " [a]" : ""));
+ if (includeAttribution) {
+ values.put(StreamItems.RES_PACKAGE, "com.android.contacts.tests");
+ int sourceIndex = randInt(labelIds.length);
+ values.put(StreamItems.RES_LABEL, labelIds[sourceIndex]);
+ if (sourceIndex < iconIds.length) {
+ values.put(StreamItems.RES_ICON, iconIds[sourceIndex]);
+ }
+ }
if (includeComments) {
values.put(StreamItems.COMMENTS, pickRandom(commentStrings));
} else {