summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChiao Cheng <chiaocheng@google.com>2012-11-07 18:20:17 -0800
committerChiao Cheng <chiaocheng@google.com>2012-11-09 13:16:16 -0800
commit63ac534dcf60e9a6c651ef2434557bec922b9a7d (patch)
tree6dc88518e13f50fd7d30ba38ef813568dabce82b
parenta23825490fdd593bceca56fd474a2f9d823c6137 (diff)
downloadandroid_packages_apps_ContactsCommon-63ac534dcf60e9a6c651ef2434557bec922b9a7d.tar.gz
android_packages_apps_ContactsCommon-63ac534dcf60e9a6c651ef2434557bec922b9a7d.tar.bz2
android_packages_apps_ContactsCommon-63ac534dcf60e9a6c651ef2434557bec922b9a7d.zip
Further clean-up of PhoneFavoriteFragment.
Moving common dependencies from Contacts to ContactsCommon. Bug: 6993891 Change-Id: I7530d13771b65f17dafa3f4f8283965622b1c71e
-rw-r--r--res/color/primary_text_color.xml22
-rw-r--r--res/drawable-hdpi/ic_contacts_holo_dark.pngbin0 -> 1490 bytes
-rw-r--r--res/drawable-hdpi/ic_divider_dashed_holo_dark.pngbin0 -> 308 bytes
-rw-r--r--res/drawable-mdpi/ic_contacts_holo_dark.pngbin0 -> 1059 bytes
-rw-r--r--res/drawable-mdpi/ic_divider_dashed_holo_dark.pngbin0 -> 293 bytes
-rw-r--r--res/drawable-xhdpi/ic_contacts_holo_dark.pngbin0 -> 2070 bytes
-rw-r--r--res/drawable-xhdpi/ic_divider_dashed_holo_dark.pngbin0 -> 314 bytes
-rw-r--r--res/layout/contact_tile_frequent.xml78
-rw-r--r--res/layout/contact_tile_frequent_phone.xml97
-rw-r--r--res/layout/contact_tile_phone_starred.xml72
-rw-r--r--res/layout/contact_tile_starred.xml80
-rw-r--r--res/layout/contact_tile_starred_quick_contact.xml78
-rw-r--r--res/layout/list_separator.xml29
-rw-r--r--res/values-sw580dp/dimens.xml19
-rw-r--r--res/values/colors.xml8
-rw-r--r--res/values/dimens.xml16
-rw-r--r--res/values/strings.xml17
-rw-r--r--res/values/styles.xml21
-rw-r--r--src/com/android/contacts/common/MoreContactUtils.java34
-rw-r--r--src/com/android/contacts/common/list/ContactTileAdapter.java680
-rw-r--r--src/com/android/contacts/common/list/ContactTileView.java191
-rw-r--r--src/com/android/contacts/common/list/PhoneNumberListAdapter.java331
22 files changed, 1773 insertions, 0 deletions
diff --git a/res/color/primary_text_color.xml b/res/color/primary_text_color.xml
new file mode 100644
index 00000000..acc2fb7a
--- /dev/null
+++ b/res/color/primary_text_color.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_activated="true" android:color="#FFFFFF" />
+ <item android:color="#333333" /> <!-- not selected -->
+
+</selector>
diff --git a/res/drawable-hdpi/ic_contacts_holo_dark.png b/res/drawable-hdpi/ic_contacts_holo_dark.png
new file mode 100644
index 00000000..e5deb011
--- /dev/null
+++ b/res/drawable-hdpi/ic_contacts_holo_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_divider_dashed_holo_dark.png b/res/drawable-hdpi/ic_divider_dashed_holo_dark.png
new file mode 100644
index 00000000..663a2f88
--- /dev/null
+++ b/res/drawable-hdpi/ic_divider_dashed_holo_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_contacts_holo_dark.png b/res/drawable-mdpi/ic_contacts_holo_dark.png
new file mode 100644
index 00000000..d08b94a4
--- /dev/null
+++ b/res/drawable-mdpi/ic_contacts_holo_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_divider_dashed_holo_dark.png b/res/drawable-mdpi/ic_divider_dashed_holo_dark.png
new file mode 100644
index 00000000..6652541c
--- /dev/null
+++ b/res/drawable-mdpi/ic_divider_dashed_holo_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_contacts_holo_dark.png b/res/drawable-xhdpi/ic_contacts_holo_dark.png
new file mode 100644
index 00000000..dc4c390f
--- /dev/null
+++ b/res/drawable-xhdpi/ic_contacts_holo_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_divider_dashed_holo_dark.png b/res/drawable-xhdpi/ic_divider_dashed_holo_dark.png
new file mode 100644
index 00000000..34e8fd25
--- /dev/null
+++ b/res/drawable-xhdpi/ic_divider_dashed_holo_dark.png
Binary files differ
diff --git a/res/layout/contact_tile_frequent.xml b/res/layout/contact_tile_frequent.xml
new file mode 100644
index 00000000..9219f56a
--- /dev/null
+++ b/res/layout/contact_tile_frequent.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<view
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ class="com.android.contacts.list.ContactTileFrequentView"
+ android:focusable="true"
+ android:background="?android:attr/selectableItemBackground"
+ android:nextFocusRight="@+id/contact_tile_quick">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <com.android.contacts.widget.LayoutSuppressingQuickContactBadge
+ android:id="@+id/contact_tile_quick"
+ android:layout_width="64dip"
+ android:layout_height="64dip"
+ android:layout_alignParentRight="true"
+ android:scaleType="centerCrop"
+ android:focusable="true" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="64dip"
+ android:orientation="vertical"
+ android:layout_alignParentBottom="true"
+ android:gravity="center_vertical"
+ android:paddingRight="80dip"
+ android:paddingLeft="8dip">
+
+ <TextView
+ android:id="@+id/contact_tile_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/primary_text_color"
+ android:textSize="18sp"
+ android:singleLine="true"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="3dip"
+ android:ellipsize="marquee" />
+
+ <TextView
+ android:id="@+id/contact_tile_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"
+ android:singleLine="true"
+ android:drawablePadding="4dip"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="3dip"
+ android:ellipsize="marquee" />
+
+ </LinearLayout>
+
+ <View
+ android:id="@+id/contact_tile_horizontal_divider"
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:background="?android:attr/listDivider"
+ android:layout_below="@id/contact_tile_quick" />
+
+ </RelativeLayout>
+
+</view>
diff --git a/res/layout/contact_tile_frequent_phone.xml b/res/layout/contact_tile_frequent_phone.xml
new file mode 100644
index 00000000..cae5ec28
--- /dev/null
+++ b/res/layout/contact_tile_frequent_phone.xml
@@ -0,0 +1,97 @@
+<?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.
+-->
+
+<!-- Layout parameters are set programmatically. -->
+<view
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/contact_tile_frequent_phone"
+ class="com.android.contacts.list.ContactTilePhoneFrequentView"
+ android:focusable="true"
+ android:background="?android:attr/selectableItemBackground"
+ android:nextFocusLeft="@+id/contact_tile_quick">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <com.android.contacts.widget.LayoutSuppressingQuickContactBadge
+ android:id="@id/contact_tile_quick"
+ android:layout_width="64dip"
+ android:layout_height="64dip"
+ android:layout_alignParentLeft="true"
+ android:nextFocusRight="@id/contact_tile_frequent_phone"
+ android:scaleType="centerCrop"
+ android:focusable="true" />
+
+ <TextView
+ android:id="@+id/contact_tile_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_marginTop="8dip"
+ android:layout_toRightOf="@id/contact_tile_quick"
+ android:singleLine="true"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="3dip"
+ android:ellipsize="marquee" />
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/contact_tile_name"
+ android:layout_toRightOf="@id/contact_tile_quick"
+ android:gravity="center_vertical">
+
+ <TextView
+ android:id="@+id/contact_tile_phone_number"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="?attr/list_item_data_width_weight"
+ android:textSize="14sp"
+ android:ellipsize="marquee"
+ android:textColor="@color/dialtacts_secondary_text_color"
+ android:layout_marginLeft="8dip"
+ android:singleLine="true"
+ android:layout_gravity="bottom" />
+
+ <TextView
+ android:id="@+id/contact_tile_phone_type"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="?attr/list_item_label_width_weight"
+ android:textSize="12sp"
+ android:ellipsize="marquee"
+ android:singleLine="true"
+ android:textAllCaps="true"
+ android:textColor="@color/dialtacts_secondary_text_color"
+ android:layout_marginLeft="8dip"
+ android:gravity="right"
+ android:layout_gravity="bottom" />
+
+ </LinearLayout>
+
+ <View
+ android:id="@+id/contact_tile_horizontal_divider"
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:background="?android:attr/listDivider"
+ android:layout_below="@id/contact_tile_quick" />
+
+ </RelativeLayout>
+
+</view>
diff --git a/res/layout/contact_tile_phone_starred.xml b/res/layout/contact_tile_phone_starred.xml
new file mode 100644
index 00000000..053ffa6b
--- /dev/null
+++ b/res/layout/contact_tile_phone_starred.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<view
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="@null"
+ android:paddingBottom="1dip"
+ android:paddingRight="1dip"
+ class="com.android.contacts.list.ContactTilePhoneStarredView" >
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <com.android.contacts.widget.LayoutSuppressingImageView
+ android:id="@+id/contact_tile_image"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerCrop" />
+
+ <TextView
+ android:id="@+id/contact_tile_name"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/contact_tile_shadowbox_height"
+ android:background="@color/contact_tile_shadow_box_color"
+ android:gravity="center_vertical"
+ android:textColor="@android:color/white"
+ android:singleLine="true"
+ android:textSize="16sp"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="3dip"
+ android:ellipsize="marquee"
+ android:layout_alignParentBottom="true"
+ android:paddingLeft="8dip"
+ android:paddingRight="47dip"
+ android:drawableRight="@drawable/ic_divider_dashed_holo_dark" />
+
+ <View
+ android:id="@+id/contact_tile_push_state"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:focusable="true"
+ android:nextFocusRight="@+id/contact_tile_secondary_button"
+ android:background="?android:attr/selectableItemBackground" />
+
+ <ImageButton
+ android:id="@id/contact_tile_secondary_button"
+ android:src="@drawable/ic_contacts_holo_dark"
+ android:background="?android:attr/selectableItemBackground"
+ android:layout_height="@dimen/contact_tile_shadowbox_height"
+ android:layout_width="48dip"
+ android:paddingRight="8dip"
+ android:paddingLeft="8dip"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentRight="true"
+ android:contentDescription="@string/description_view_contact_detail" />
+
+ </RelativeLayout>
+
+</view>
diff --git a/res/layout/contact_tile_starred.xml b/res/layout/contact_tile_starred.xml
new file mode 100644
index 00000000..cfc74d80
--- /dev/null
+++ b/res/layout/contact_tile_starred.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<view
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="@null"
+ android:paddingBottom="1dip"
+ android:paddingRight="1dip"
+ class="com.android.contacts.list.ContactTileStarredView" >
+
+ <RelativeLayout
+ android:id="@+id/contact_tile_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <com.android.contacts.widget.LayoutSuppressingImageView
+ android:id="@+id/contact_tile_image"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerCrop" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/contact_tile_shadowbox_height"
+ android:orientation="vertical"
+ android:background="@color/contact_tile_shadow_box_color"
+ android:layout_alignParentBottom="true"
+ android:gravity="center_vertical"
+ android:paddingRight="8dip"
+ android:paddingLeft="8dip">
+
+ <TextView
+ android:id="@+id/contact_tile_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@android:color/white"
+ android:textSize="16sp"
+ android:singleLine="true"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="3dip"
+ android:ellipsize="marquee" />
+
+ <TextView
+ android:id="@+id/contact_tile_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="@color/people_contact_tile_status_color"
+ android:singleLine="true"
+ android:drawablePadding="4dip"
+ android:paddingBottom="4dip"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="3dip"
+ android:layout_marginTop="-3dip"
+ android:ellipsize="marquee" />
+
+ </LinearLayout>
+
+ <View
+ android:id="@+id/contact_tile_push_state"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:focusable="true"
+ android:background="?android:attr/selectableItemBackground" />
+
+ </RelativeLayout>
+
+</view>
diff --git a/res/layout/contact_tile_starred_quick_contact.xml b/res/layout/contact_tile_starred_quick_contact.xml
new file mode 100644
index 00000000..a396c41b
--- /dev/null
+++ b/res/layout/contact_tile_starred_quick_contact.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<view
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:paddingBottom="1dip"
+ android:paddingRight="1dip"
+ android:background="@null"
+ class="com.android.contacts.list.ContactTileStarredView" >
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <com.android.contacts.widget.LayoutSuppressingImageView
+ android:id="@+id/contact_tile_image"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerCrop" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/contact_tile_shadowbox_height"
+ android:orientation="vertical"
+ android:background="@color/contact_tile_shadow_box_color"
+ android:layout_alignParentBottom="true"
+ android:gravity="center_vertical"
+ android:paddingRight="8dip"
+ android:paddingLeft="8dip">
+
+ <TextView
+ android:id="@+id/contact_tile_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@android:color/white"
+ android:textSize="16sp"
+ android:singleLine="true"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="3dip"
+ android:ellipsize="marquee" />
+
+ <TextView
+ android:id="@+id/contact_tile_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="@color/people_contact_tile_status_color"
+ android:singleLine="true"
+ android:drawablePadding="4dip"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="3dip"
+ android:layout_marginTop="-3dip"
+ android:ellipsize="marquee" />
+
+ </LinearLayout>
+
+ <QuickContactBadge
+ android:id="@+id/contact_tile_quick"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:focusable="true"
+ android:background="@null" />
+
+ </RelativeLayout>
+
+</view>
diff --git a/res/layout/list_separator.xml b/res/layout/list_separator.xml
new file mode 100644
index 00000000..d94e18c4
--- /dev/null
+++ b/res/layout/list_separator.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip"
+ android:focusable="false">
+ <TextView
+ android:id="@+id/title"
+ style="@style/ContactListSeparatorTextViewStyle"
+ android:paddingLeft="8dip"
+ android:paddingRight="8dip" />
+</FrameLayout>
diff --git a/res/values-sw580dp/dimens.xml b/res/values-sw580dp/dimens.xml
new file mode 100644
index 00000000..bdbc0d4a
--- /dev/null
+++ b/res/values-sw580dp/dimens.xml
@@ -0,0 +1,19 @@
+<!--
+ ~ Copyright (C) 2012 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
+ -->
+
+<resources>
+ <dimen name="detail_item_side_margin">0dip</dimen>
+</resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 13eadd35..48ef4ece 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -25,4 +25,12 @@
<!-- Color of image view placeholder. -->
<color name="image_placeholder">#DDDDDD</color>
+ <!-- Secondary text color in the Phone app -->
+ <color name="dialtacts_secondary_text_color">#888888</color>
+
+ <!-- Color of the semi-transparent shadow box on contact tiles -->
+ <color name="contact_tile_shadow_box_color">#7F000000</color>
+
+ <!-- Color of the status message for starred contacts in the People app -->
+ <color name="people_contact_tile_status_color">#CCCCCC</color>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index c17234c5..97e6fe78 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -24,4 +24,20 @@
Right now the drawable has implicit 32dip minimal height, which is confusing.
This value is for making the hidden configuration explicit in xml. -->
<dimen name="list_section_divider_min_height">32dip</dimen>
+
+ <!-- Vertical and horizontal padding in between contact tiles -->
+ <dimen name="contact_tile_divider_padding">1dip</dimen>
+
+ <!-- Left and right padding for a contact detail item -->
+ <dimen name="detail_item_side_margin">16dip</dimen>
+
+ <!-- ContactTile Layouts -->
+ <!--
+ Use sp instead of dip so that the shadowbox heights can all scale uniformly
+ when the font size is scaled for accessibility purposes
+ -->
+ <dimen name="contact_tile_shadowbox_height">48sp</dimen>
+
+ <!-- Top padding of the ListView in the contact tile list -->
+ <dimen name="contact_tile_list_padding_top">0dip</dimen>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 87ea719c..cc855664 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -177,4 +177,21 @@
<!-- 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 text displayed on the divider for the Favorites tab in Phone app indicating that items below it are frequently called as opposed to starred contacts [CHAR LIMIT = 39] -->
+ <string name="favoritesFrequentCalled">Frequently called</string>
+
+ <!-- The text displayed on the divider for the Favorites tab in People app indicating that items below it are frequently contacted [CHAR LIMIT = 39] -->
+ <string name="favoritesFrequentContacted">Frequently contacted</string>
+
+ <!-- String describing a contact picture that introduces users to the contact detail screen.
+
+ Used by AccessibilityService to announce the purpose of the button.
+
+ [CHAR LIMIT=NONE]
+ -->
+ <string name="description_view_contact_detail" msgid="2795575601596468581">View contact</string>
+
+ <!-- Contact list filter selection indicating that the list shows all contacts with phone numbers [CHAR LIMIT=64] -->
+ <string name="list_filter_phones">All contacts with phone numbers</string>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 45137e73..7522f99a 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -19,4 +19,25 @@
<style name="DirectoryHeader">
<item name="android:background">@android:color/transparent</item>
</style>
+
+ <!-- TextView style with blue underline. It is most suitable for headers.
+
+This is similar to ?android:attr/listSeparatorTextView but uses different
+background and text color. See also android:style/Widget.Holo.TextView.ListSeparator
+(which is private, so we cannot specify it as a parent style). -->
+ <style name="ContactListSeparatorTextViewStyle">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <!-- See comments for @dimen/list_section_divider_min_height -->
+ <item name="android:minHeight">@dimen/list_section_divider_min_height</item>
+ <item name="android:background">@drawable/list_section_divider_holo_custom</item>
+ <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
+ <item name="android:textStyle">bold</item>
+ <item name="android:textColor">@color/people_app_theme_color</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:paddingLeft">8dip</item>
+ <item name="android:ellipsize">end</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:textAllCaps">true</item>
+ </style>
</resources>
diff --git a/src/com/android/contacts/common/MoreContactUtils.java b/src/com/android/contacts/common/MoreContactUtils.java
index cceea6a0..c37e29c6 100644
--- a/src/com/android/contacts/common/MoreContactUtils.java
+++ b/src/com/android/contacts/common/MoreContactUtils.java
@@ -16,9 +16,13 @@
package com.android.contacts.common;
+import android.content.Context;
+import android.graphics.Rect;
import android.provider.ContactsContract;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
+import android.view.View;
+import android.widget.TextView;
/**
* Shared static contact utility methods.
@@ -85,4 +89,34 @@ public class MoreContactUtils {
index2++;
}
}
+
+ /**
+ * Returns the {@link android.graphics.Rect} with left, top, right, and bottom coordinates
+ * that are equivalent to the given {@link android.view.View}'s bounds. This is equivalent to
+ * how the target {@link android.graphics.Rect} is calculated in
+ * {@link android.provider.ContactsContract.QuickContact#showQuickContact}.
+ */
+ public static Rect getTargetRectFromView(Context context, View view) {
+ final float appScale = context.getResources().getCompatibilityInfo().applicationScale;
+ final int[] pos = new int[2];
+ view.getLocationOnScreen(pos);
+
+ final Rect rect = new Rect();
+ rect.left = (int) (pos[0] * appScale + 0.5f);
+ rect.top = (int) (pos[1] * appScale + 0.5f);
+ rect.right = (int) ((pos[0] + view.getWidth()) * appScale + 0.5f);
+ rect.bottom = (int) ((pos[1] + view.getHeight()) * appScale + 0.5f);
+ return rect;
+ }
+
+ /**
+ * Returns a header view based on the R.layout.list_separator, where the
+ * containing {@link android.widget.TextView} is set using the given textResourceId.
+ */
+ public static View createHeaderView(Context context, int textResourceId) {
+ View view = View.inflate(context, R.layout.list_separator, null);
+ TextView textView = (TextView) view.findViewById(R.id.title);
+ textView.setText(context.getString(textResourceId));
+ return view;
+ }
}
diff --git a/src/com/android/contacts/common/list/ContactTileAdapter.java b/src/com/android/contacts/common/list/ContactTileAdapter.java
new file mode 100644
index 00000000..50b5ee39
--- /dev/null
+++ b/src/com/android/contacts/common/list/ContactTileAdapter.java
@@ -0,0 +1,680 @@
+/*
+ * 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.common.list;
+
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.Contacts;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
+
+import com.android.contacts.common.ContactPhotoManager;
+import com.android.contacts.common.ContactPresenceIconUtil;
+import com.android.contacts.common.ContactStatusUtil;
+import com.android.contacts.common.ContactTileLoaderFactory;
+import com.android.contacts.common.MoreContactUtils;
+import com.android.contacts.common.R;
+
+import java.util.ArrayList;
+
+/**
+ * Arranges contacts favorites according to provided {@link DisplayType}.
+ * Also allows for a configurable number of columns and {@link DisplayType}
+ */
+public class ContactTileAdapter extends BaseAdapter {
+ private static final String TAG = ContactTileAdapter.class.getSimpleName();
+
+ private DisplayType mDisplayType;
+ private ContactTileView.Listener mListener;
+ private Context mContext;
+ private Resources mResources;
+ protected Cursor mContactCursor = null;
+ private ContactPhotoManager mPhotoManager;
+ protected int mNumFrequents;
+
+ /**
+ * Index of the first NON starred contact in the {@link Cursor}
+ * Only valid when {@link DisplayType#STREQUENT} is true
+ */
+ private int mDividerPosition;
+ protected int mColumnCount;
+ private int mStarredIndex;
+
+ protected int mIdIndex;
+ protected int mLookupIndex;
+ protected int mPhotoUriIndex;
+ protected int mNameIndex;
+ protected int mPresenceIndex;
+ protected int mStatusIndex;
+
+ /**
+ * Only valid when {@link DisplayType#STREQUENT_PHONE_ONLY} is true
+ */
+ private int mPhoneNumberIndex;
+ private int mPhoneNumberTypeIndex;
+ private int mPhoneNumberLabelIndex;
+
+ private boolean mIsQuickContactEnabled = false;
+ private final int mPaddingInPixels;
+
+ /**
+ * Configures the adapter to filter and display contacts using different view types.
+ * TODO: Create Uris to support getting Starred_only and Frequent_only cursors.
+ */
+ public enum DisplayType {
+ /**
+ * Displays a mixed view type of starred and frequent contacts
+ */
+ STREQUENT,
+
+ /**
+ * Displays a mixed view type of starred and frequent contacts based on phone data.
+ * Also includes secondary touch target.
+ */
+ STREQUENT_PHONE_ONLY,
+
+ /**
+ * Display only starred contacts
+ */
+ STARRED_ONLY,
+
+ /**
+ * Display only most frequently contacted
+ */
+ FREQUENT_ONLY,
+
+ /**
+ * Display all contacts from a group in the cursor
+ * Use {@link com.android.contacts.GroupMemberLoader}
+ * when passing {@link Cursor} into loadFromCusor method.
+ *
+ * Group member logic has been moved into GroupMemberTileAdapter. This constant is still
+ * needed by calling classes.
+ */
+ GROUP_MEMBERS
+ }
+
+ public ContactTileAdapter(Context context, ContactTileView.Listener listener, int numCols,
+ DisplayType displayType) {
+ mListener = listener;
+ mContext = context;
+ mResources = context.getResources();
+ mColumnCount = (displayType == DisplayType.FREQUENT_ONLY ? 1 : numCols);
+ mDisplayType = displayType;
+ mNumFrequents = 0;
+
+ // Converting padding in dips to padding in pixels
+ mPaddingInPixels = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.contact_tile_divider_padding);
+
+ bindColumnIndices();
+ }
+
+ public void setPhotoLoader(ContactPhotoManager photoLoader) {
+ mPhotoManager = photoLoader;
+ }
+
+ public void setColumnCount(int columnCount) {
+ mColumnCount = columnCount;
+ }
+
+ public void setDisplayType(DisplayType displayType) {
+ mDisplayType = displayType;
+ }
+
+ public void enableQuickContact(boolean enableQuickContact) {
+ mIsQuickContactEnabled = enableQuickContact;
+ }
+
+ /**
+ * Sets the column indices for expected {@link Cursor}
+ * based on {@link DisplayType}.
+ */
+ protected void bindColumnIndices() {
+ mIdIndex = ContactTileLoaderFactory.CONTACT_ID;
+ mLookupIndex = ContactTileLoaderFactory.LOOKUP_KEY;
+ mPhotoUriIndex = ContactTileLoaderFactory.PHOTO_URI;
+ mNameIndex = ContactTileLoaderFactory.DISPLAY_NAME;
+ mStarredIndex = ContactTileLoaderFactory.STARRED;
+ mPresenceIndex = ContactTileLoaderFactory.CONTACT_PRESENCE;
+ mStatusIndex = ContactTileLoaderFactory.CONTACT_STATUS;
+
+ mPhoneNumberIndex = ContactTileLoaderFactory.PHONE_NUMBER;
+ mPhoneNumberTypeIndex = ContactTileLoaderFactory.PHONE_NUMBER_TYPE;
+ mPhoneNumberLabelIndex = ContactTileLoaderFactory.PHONE_NUMBER_LABEL;
+ }
+
+ /**
+ * Gets the number of frequents from the passed in cursor.
+ *
+ * This methods is needed so the GroupMemberTileAdapter can override this.
+ *
+ * @param cursor The cursor to get number of frequents from.
+ */
+ protected void saveNumFrequentsFromCursor(Cursor cursor) {
+
+ // count the number of frequents
+ switch (mDisplayType) {
+ case STARRED_ONLY:
+ mNumFrequents = 0;
+ break;
+ case STREQUENT:
+ case STREQUENT_PHONE_ONLY:
+ mNumFrequents = cursor.getCount() - mDividerPosition;
+ break;
+ case FREQUENT_ONLY:
+ mNumFrequents = cursor.getCount();
+ break;
+ default:
+ throw new IllegalArgumentException("Unrecognized DisplayType " + mDisplayType);
+ }
+ }
+
+ /**
+ * Creates {@link ContactTileView}s for each item in {@link Cursor}.
+ *
+ * Else use {@link ContactTileLoaderFactory}
+ */
+ public void setContactCursor(Cursor cursor) {
+ mContactCursor = cursor;
+ mDividerPosition = getDividerPosition(cursor);
+
+ saveNumFrequentsFromCursor(cursor);
+
+ // cause a refresh of any views that rely on this data
+ notifyDataSetChanged();
+ }
+
+ /**
+ * Iterates over the {@link Cursor}
+ * Returns position of the first NON Starred Contact
+ * Returns -1 if {@link DisplayType#STARRED_ONLY}
+ * Returns 0 if {@link DisplayType#FREQUENT_ONLY}
+ */
+ protected int getDividerPosition(Cursor cursor) {
+ if (cursor == null || cursor.isClosed()) {
+ throw new IllegalStateException("Unable to access cursor");
+ }
+
+ switch (mDisplayType) {
+ case STREQUENT:
+ case STREQUENT_PHONE_ONLY:
+ cursor.moveToPosition(-1);
+ while (cursor.moveToNext()) {
+ if (cursor.getInt(mStarredIndex) == 0) {
+ return cursor.getPosition();
+ }
+ }
+ break;
+ case STARRED_ONLY:
+ // There is no divider
+ return -1;
+ case FREQUENT_ONLY:
+ // Divider is first
+ return 0;
+ default:
+ throw new IllegalStateException("Unrecognized DisplayType " + mDisplayType);
+ }
+
+ // There are not NON Starred contacts in cursor
+ // Set divider positon to end
+ return cursor.getCount();
+ }
+
+ protected ContactEntry createContactEntryFromCursor(Cursor cursor, int position) {
+ // If the loader was canceled we will be given a null cursor.
+ // In that case, show an empty list of contacts.
+ if (cursor == null || cursor.isClosed() || cursor.getCount() <= position) return null;
+
+ cursor.moveToPosition(position);
+ long id = cursor.getLong(mIdIndex);
+ String photoUri = cursor.getString(mPhotoUriIndex);
+ String lookupKey = cursor.getString(mLookupIndex);
+
+ ContactEntry contact = new ContactEntry();
+ 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(
+ Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), id);
+
+ // Set phone number and label
+ if (mDisplayType == DisplayType.STREQUENT_PHONE_ONLY) {
+ int phoneNumberType = cursor.getInt(mPhoneNumberTypeIndex);
+ String phoneNumberCustomLabel = cursor.getString(mPhoneNumberLabelIndex);
+ contact.phoneLabel = (String) Phone.getTypeLabel(mResources, phoneNumberType,
+ phoneNumberCustomLabel);
+ contact.phoneNumber = cursor.getString(mPhoneNumberIndex);
+ } else {
+ // Set presence icon and status message
+ Drawable icon = null;
+ int presence = 0;
+ if (!cursor.isNull(mPresenceIndex)) {
+ presence = cursor.getInt(mPresenceIndex);
+ icon = ContactPresenceIconUtil.getPresenceIcon(mContext, presence);
+ }
+ contact.presenceIcon = icon;
+
+ String statusMessage = null;
+ if (mStatusIndex != 0 && !cursor.isNull(mStatusIndex)) {
+ statusMessage = cursor.getString(mStatusIndex);
+ }
+ // If there is no status message from the contact, but there was a presence value,
+ // then use the default status message string
+ if (statusMessage == null && presence != 0) {
+ statusMessage = ContactStatusUtil.getStatusString(mContext, presence);
+ }
+ contact.status = statusMessage;
+ }
+
+ return contact;
+ }
+
+ /**
+ * Returns the number of frequents that will be displayed in the list.
+ */
+ public int getNumFrequents() {
+ return mNumFrequents;
+ }
+
+ @Override
+ public int getCount() {
+ if (mContactCursor == null || mContactCursor.isClosed()) {
+ return 0;
+ }
+
+ switch (mDisplayType) {
+ case STARRED_ONLY:
+ return getRowCount(mContactCursor.getCount());
+ case STREQUENT:
+ case STREQUENT_PHONE_ONLY:
+ // Takes numbers of rows the Starred Contacts Occupy
+ int starredRowCount = getRowCount(mDividerPosition);
+
+ // Compute the frequent row count which is 1 plus the number of frequents
+ // (to account for the divider) or 0 if there are no frequents.
+ int frequentRowCount = mNumFrequents == 0 ? 0 : mNumFrequents + 1;
+
+ // Return the number of starred plus frequent rows
+ return starredRowCount + frequentRowCount;
+ case FREQUENT_ONLY:
+ // Number of frequent contacts
+ return mContactCursor.getCount();
+ default:
+ throw new IllegalArgumentException("Unrecognized DisplayType " + mDisplayType);
+ }
+ }
+
+ /**
+ * Returns the number of rows required to show the provided number of entries
+ * with the current number of columns.
+ */
+ protected int getRowCount(int entryCount) {
+ return entryCount == 0 ? 0 : ((entryCount - 1) / mColumnCount) + 1;
+ }
+
+ public int getColumnCount() {
+ return mColumnCount;
+ }
+
+ /**
+ * Returns an ArrayList of the {@link ContactEntry}s that are to appear
+ * on the row for the given position.
+ */
+ @Override
+ public ArrayList<ContactEntry> getItem(int position) {
+ ArrayList<ContactEntry> resultList = new ArrayList<ContactEntry>(mColumnCount);
+ int contactIndex = position * mColumnCount;
+
+ switch (mDisplayType) {
+ case FREQUENT_ONLY:
+ resultList.add(createContactEntryFromCursor(mContactCursor, position));
+ break;
+ case STARRED_ONLY:
+ for (int columnCounter = 0; columnCounter < mColumnCount; columnCounter++) {
+ resultList.add(createContactEntryFromCursor(mContactCursor, contactIndex));
+ contactIndex++;
+ }
+ break;
+ case STREQUENT:
+ case STREQUENT_PHONE_ONLY:
+ if (position < getRowCount(mDividerPosition)) {
+ for (int columnCounter = 0; columnCounter < mColumnCount &&
+ contactIndex != mDividerPosition; columnCounter++) {
+ resultList.add(createContactEntryFromCursor(mContactCursor, contactIndex));
+ contactIndex++;
+ }
+ } else {
+ /*
+ * Current position minus how many rows are before the divider and
+ * Minus 1 for the divider itself provides the relative index of the frequent
+ * contact being displayed. Then add the dividerPostion to give the offset
+ * into the contacts cursor to get the absoulte index.
+ */
+ contactIndex = position - getRowCount(mDividerPosition) - 1 + mDividerPosition;
+ resultList.add(createContactEntryFromCursor(mContactCursor, contactIndex));
+ }
+ break;
+ default:
+ throw new IllegalStateException("Unrecognized DisplayType " + mDisplayType);
+ }
+ return resultList;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ // As we show several selectable items for each ListView row,
+ // we can not determine a stable id. But as we don't rely on ListView's selection,
+ // this should not be a problem.
+ return position;
+ }
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ return (mDisplayType != DisplayType.STREQUENT &&
+ mDisplayType != DisplayType.STREQUENT_PHONE_ONLY);
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return position != getRowCount(mDividerPosition);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ int itemViewType = getItemViewType(position);
+
+ if (itemViewType == ViewTypes.DIVIDER) {
+ // Checking For Divider First so not to cast convertView
+ return convertView == null ? getDivider() : convertView;
+ }
+
+ ContactTileRow contactTileRowView = (ContactTileRow) convertView;
+ ArrayList<ContactEntry> contactList = getItem(position);
+
+ if (contactTileRowView == null) {
+ // Creating new row if needed
+ contactTileRowView = new ContactTileRow(mContext, itemViewType);
+ }
+
+ contactTileRowView.configureRow(contactList, position == getCount() - 1);
+ return contactTileRowView;
+ }
+
+ /**
+ * Divider uses a list_seperator.xml along with text to denote
+ * the most frequently contacted contacts.
+ */
+ public View getDivider() {
+ return MoreContactUtils.createHeaderView(mContext,
+ mDisplayType == DisplayType.STREQUENT_PHONE_ONLY ?
+ R.string.favoritesFrequentCalled : R.string.favoritesFrequentContacted);
+ }
+
+ private int getLayoutResourceId(int viewType) {
+ switch (viewType) {
+ case ViewTypes.STARRED:
+ return mIsQuickContactEnabled ?
+ R.layout.contact_tile_starred_quick_contact : R.layout.contact_tile_starred;
+ case ViewTypes.FREQUENT:
+ return mDisplayType == DisplayType.STREQUENT_PHONE_ONLY ?
+ R.layout.contact_tile_frequent_phone : R.layout.contact_tile_frequent;
+ case ViewTypes.STARRED_PHONE:
+ return R.layout.contact_tile_phone_starred;
+ default:
+ throw new IllegalArgumentException("Unrecognized viewType " + viewType);
+ }
+ }
+ @Override
+ public int getViewTypeCount() {
+ return ViewTypes.COUNT;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ /*
+ * Returns view type based on {@link DisplayType}.
+ * {@link DisplayType#STARRED_ONLY} and {@link DisplayType#GROUP_MEMBERS}
+ * are {@link ViewTypes#STARRED}.
+ * {@link DisplayType#FREQUENT_ONLY} is {@link ViewTypes#FREQUENT}.
+ * {@link DisplayType#STREQUENT} mixes both {@link ViewTypes}
+ * and also adds in {@link ViewTypes#DIVIDER}.
+ */
+ switch (mDisplayType) {
+ case STREQUENT:
+ if (position < getRowCount(mDividerPosition)) {
+ return ViewTypes.STARRED;
+ } else if (position == getRowCount(mDividerPosition)) {
+ return ViewTypes.DIVIDER;
+ } else {
+ return ViewTypes.FREQUENT;
+ }
+ case STREQUENT_PHONE_ONLY:
+ if (position < getRowCount(mDividerPosition)) {
+ return ViewTypes.STARRED_PHONE;
+ } else if (position == getRowCount(mDividerPosition)) {
+ return ViewTypes.DIVIDER;
+ } else {
+ return ViewTypes.FREQUENT;
+ }
+ case STARRED_ONLY:
+ return ViewTypes.STARRED;
+ case FREQUENT_ONLY:
+ return ViewTypes.FREQUENT;
+ default:
+ throw new IllegalStateException("Unrecognized DisplayType " + mDisplayType);
+ }
+ }
+
+ /**
+ * Returns the "frequent header" position. Only available when STREQUENT or
+ * STREQUENT_PHONE_ONLY is used for its display type.
+ */
+ public int getFrequentHeaderPosition() {
+ return getRowCount(mDividerPosition);
+ }
+
+ /**
+ * Acts as a row item composed of {@link ContactTileView}
+ *
+ * TODO: FREQUENT doesn't really need it. Just let {@link #getView} return
+ */
+ private class ContactTileRow extends FrameLayout {
+ private int mItemViewType;
+ private int mLayoutResId;
+
+ public ContactTileRow(Context context, int itemViewType) {
+ super(context);
+ mItemViewType = itemViewType;
+ mLayoutResId = getLayoutResourceId(mItemViewType);
+ }
+
+ /**
+ * Configures the row to add {@link ContactEntry}s information to the views
+ */
+ public void configureRow(ArrayList<ContactEntry> list, boolean isLastRow) {
+ int columnCount = mItemViewType == ViewTypes.FREQUENT ? 1 : mColumnCount;
+
+ // Adding tiles to row and filling in contact information
+ for (int columnCounter = 0; columnCounter < columnCount; columnCounter++) {
+ ContactEntry entry =
+ columnCounter < list.size() ? list.get(columnCounter) : null;
+ addTileFromEntry(entry, columnCounter, isLastRow);
+ }
+ }
+
+ private void addTileFromEntry(ContactEntry entry, int childIndex, boolean isLastRow) {
+ final ContactTileView contactTile;
+
+ if (getChildCount() <= childIndex) {
+ contactTile = (ContactTileView) inflate(mContext, mLayoutResId, null);
+ // Note: the layoutparam set here is only actually used for FREQUENT.
+ // We override onMeasure() for STARRED and we don't care the layout param there.
+ Resources resources = mContext.getResources();
+ FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ params.setMargins(
+ resources.getDimensionPixelSize(R.dimen.detail_item_side_margin),
+ 0,
+ resources.getDimensionPixelSize(R.dimen.detail_item_side_margin),
+ 0);
+ contactTile.setLayoutParams(params);
+ contactTile.setPhotoManager(mPhotoManager);
+ contactTile.setListener(mListener);
+ addView(contactTile);
+ } else {
+ contactTile = (ContactTileView) getChildAt(childIndex);
+ }
+ contactTile.loadFromContact(entry);
+
+ switch (mItemViewType) {
+ case ViewTypes.STARRED_PHONE:
+ case ViewTypes.STARRED:
+ // Setting divider visibilities
+ contactTile.setPadding(0, 0,
+ childIndex >= mColumnCount - 1 ? 0 : mPaddingInPixels,
+ isLastRow ? 0 : mPaddingInPixels);
+ break;
+ case ViewTypes.FREQUENT:
+ contactTile.setHorizontalDividerVisibility(
+ isLastRow ? View.GONE : View.VISIBLE);
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ switch (mItemViewType) {
+ case ViewTypes.STARRED_PHONE:
+ case ViewTypes.STARRED:
+ onLayoutForTiles();
+ return;
+ default:
+ super.onLayout(changed, left, top, right, bottom);
+ return;
+ }
+ }
+
+ private void onLayoutForTiles() {
+ final int count = getChildCount();
+
+ // Just line up children horizontally.
+ int childLeft = 0;
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+
+ // Note MeasuredWidth includes the padding.
+ final int childWidth = child.getMeasuredWidth();
+ child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());
+ childLeft += childWidth;
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ switch (mItemViewType) {
+ case ViewTypes.STARRED_PHONE:
+ case ViewTypes.STARRED:
+ onMeasureForTiles(widthMeasureSpec);
+ return;
+ default:
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ return;
+ }
+ }
+
+ private void onMeasureForTiles(int widthMeasureSpec) {
+ final int width = MeasureSpec.getSize(widthMeasureSpec);
+
+ final int childCount = getChildCount();
+ if (childCount == 0) {
+ // Just in case...
+ setMeasuredDimension(width, 0);
+ return;
+ }
+
+ // 1. Calculate image size.
+ // = ([total width] - [total padding]) / [child count]
+ //
+ // 2. Set it to width/height of each children.
+ // If we have a remainder, some tiles will have 1 pixel larger width than its height.
+ //
+ // 3. Set the dimensions of itself.
+ // Let width = given width.
+ // Let height = image size + bottom paddding.
+
+ final int totalPaddingsInPixels = (mColumnCount - 1) * mPaddingInPixels;
+
+ // Preferred width / height for images (excluding the padding).
+ // The actual width may be 1 pixel larger than this if we have a remainder.
+ final int imageSize = (width - totalPaddingsInPixels) / mColumnCount;
+ final int remainder = width - (imageSize * mColumnCount) - totalPaddingsInPixels;
+
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+ final int childWidth = imageSize + child.getPaddingRight()
+ // Compensate for the remainder
+ + (i < remainder ? 1 : 0);
+ final int childHeight = imageSize + child.getPaddingBottom();
+ child.measure(
+ MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY)
+ );
+ }
+ setMeasuredDimension(width, imageSize + getChildAt(0).getPaddingBottom());
+ }
+
+ @Override
+ public void sendAccessibilityEvent(int eventType) {
+ // This method is called when the child tile is INVISIBLE (meaning "empty"), and the
+ // Accessibility Manager needs to find alternative content description to speak.
+ // Here, we ignore the default behavior, since we don't want to let the manager speak
+ // a contact name for the tile next to the INVISIBLE tile.
+ }
+ }
+
+ /**
+ * Class to hold contact information
+ */
+ public static class ContactEntry {
+ public String name;
+ public String status;
+ public String phoneLabel;
+ public String phoneNumber;
+ public Uri photoUri;
+ public Uri lookupKey;
+ public Drawable presenceIcon;
+ }
+
+ protected static class ViewTypes {
+ public static final int COUNT = 4;
+ public static final int STARRED = 0;
+ public static final int DIVIDER = 1;
+ public static final int FREQUENT = 2;
+ public static final int STARRED_PHONE = 3;
+ }
+}
diff --git a/src/com/android/contacts/common/list/ContactTileView.java b/src/com/android/contacts/common/list/ContactTileView.java
new file mode 100644
index 00000000..e30ed49a
--- /dev/null
+++ b/src/com/android/contacts/common/list/ContactTileView.java
@@ -0,0 +1,191 @@
+/*
+ * 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.common.list;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.QuickContactBadge;
+import android.widget.TextView;
+
+import com.android.contacts.common.ContactPhotoManager;
+import com.android.contacts.common.MoreContactUtils;
+import com.android.contacts.common.R;
+
+/**
+ * A ContactTile displays a contact's picture and name
+ */
+public abstract class ContactTileView extends FrameLayout {
+ private final static String TAG = ContactTileView.class.getSimpleName();
+
+ private Uri mLookupUri;
+ private ImageView mPhoto;
+ private QuickContactBadge mQuickContact;
+ private TextView mName;
+ private TextView mStatus;
+ private TextView mPhoneLabel;
+ private TextView mPhoneNumber;
+ private ContactPhotoManager mPhotoManager = null;
+ private View mPushState;
+ private View mHorizontalDivider;
+ protected Listener mListener;
+
+ public ContactTileView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mName = (TextView) findViewById(R.id.contact_tile_name);
+
+ mQuickContact = (QuickContactBadge) findViewById(R.id.contact_tile_quick);
+ mPhoto = (ImageView) findViewById(R.id.contact_tile_image);
+ 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 = findViewById(R.id.contact_tile_push_state);
+ mHorizontalDivider = findViewById(R.id.contact_tile_horizontal_divider);
+
+ OnClickListener listener = createClickListener();
+
+ if(mPushState != null) {
+ mPushState.setOnClickListener(listener);
+ } else {
+ setOnClickListener(listener);
+ }
+ }
+
+ protected OnClickListener createClickListener() {
+ return new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mListener == null) return;
+ mListener.onContactSelected(
+ getLookupUri(),
+ MoreContactUtils.getTargetRectFromView(mContext, ContactTileView.this));
+ }
+ };
+ }
+
+ public void setPhotoManager(ContactPhotoManager photoManager) {
+ mPhotoManager = photoManager;
+ }
+
+ /**
+ * Populates the data members to be displayed from the
+ * fields in {@link com.android.contacts.common.list.ContactTileAdapter.ContactEntry}
+ */
+ public void loadFromContact(ContactTileAdapter.ContactEntry entry) {
+
+ if (entry != null) {
+ mName.setText(entry.name);
+ mLookupUri = entry.lookupKey;
+
+ if (mStatus != null) {
+ if (entry.status == null) {
+ mStatus.setVisibility(View.GONE);
+ } else {
+ mStatus.setText(entry.status);
+ mStatus.setCompoundDrawablesWithIntrinsicBounds(entry.presenceIcon,
+ null, null, null);
+ mStatus.setVisibility(View.VISIBLE);
+ }
+ }
+
+ if (mPhoneLabel != null) {
+ mPhoneLabel.setText(entry.phoneLabel);
+ }
+
+ if (mPhoneNumber != null) {
+ // TODO: Format number correctly
+ mPhoneNumber.setText(entry.phoneNumber);
+ }
+
+ setVisibility(View.VISIBLE);
+
+ if (mPhotoManager != null) {
+ if (mPhoto != null) {
+ mPhotoManager.loadPhoto(mPhoto, entry.photoUri, getApproximateImageSize(),
+ isDarkTheme());
+
+ if (mQuickContact != null) {
+ mQuickContact.assignContactUri(mLookupUri);
+ }
+ } else if (mQuickContact != null) {
+ mQuickContact.assignContactUri(mLookupUri);
+ mPhotoManager.loadPhoto(mQuickContact, entry.photoUri,
+ getApproximateImageSize(), isDarkTheme());
+ }
+ } else {
+ Log.w(TAG, "contactPhotoManager not set");
+ }
+
+ if (mPushState != null) {
+ mPushState.setContentDescription(entry.name);
+ } else if (mQuickContact != null) {
+ mQuickContact.setContentDescription(entry.name);
+ }
+ } else {
+ setVisibility(View.INVISIBLE);
+ }
+ }
+
+ public void setListener(Listener listener) {
+ mListener = listener;
+ }
+
+ public void setHorizontalDividerVisibility(int visibility) {
+ if (mHorizontalDivider != null) mHorizontalDivider.setVisibility(visibility);
+ }
+
+ public Uri getLookupUri() {
+ return mLookupUri;
+ }
+
+ protected QuickContactBadge getQuickContact() {
+ return mQuickContact;
+ }
+
+ /**
+ * Implemented by subclasses to estimate the size of the picture. This can return -1 if only
+ * a thumbnail is shown anyway
+ */
+ protected abstract int getApproximateImageSize();
+
+ protected abstract boolean isDarkTheme();
+
+ public interface Listener {
+ /**
+ * Notification that the contact was selected; no specific action is dictated.
+ */
+ void onContactSelected(Uri contactLookupUri, Rect viewRect);
+ /**
+ * Notification that the specified number is to be called.
+ */
+ void onCallNumberDirectly(String phoneNumber);
+ /**
+ * @return The width of each tile. This doesn't have to be a precise number (e.g. paddings
+ * can be ignored), but is used to load the correct picture size from the database
+ */
+ int getApproximateTileWidth();
+ }
+}
diff --git a/src/com/android/contacts/common/list/PhoneNumberListAdapter.java b/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
new file mode 100644
index 00000000..c62b6b1f
--- /dev/null
+++ b/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.contacts.common.list;
+
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.CursorLoader;
+import android.database.Cursor;
+import android.net.Uri;
+import android.net.Uri.Builder;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Callable;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.SipAddress;
+import android.provider.ContactsContract.ContactCounts;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Directory;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.contacts.common.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A cursor adapter for the {@link Phone#CONTENT_ITEM_TYPE} and
+ * {@link SipAddress#CONTENT_ITEM_TYPE}.
+ *
+ * By default this adapter just handles phone numbers. When {@link #setUseCallableUri(boolean)} is
+ * called with "true", this adapter starts handling SIP addresses too, by using {@link Callable}
+ * API instead of {@link Phone}.
+ */
+public class PhoneNumberListAdapter extends ContactEntryListAdapter {
+ private static final String TAG = PhoneNumberListAdapter.class.getSimpleName();
+
+ protected static class PhoneQuery {
+ private static final String[] PROJECTION_PRIMARY = new String[] {
+ Phone._ID, // 0
+ Phone.TYPE, // 1
+ Phone.LABEL, // 2
+ Phone.NUMBER, // 3
+ Phone.CONTACT_ID, // 4
+ Phone.LOOKUP_KEY, // 5
+ Phone.PHOTO_ID, // 6
+ Phone.DISPLAY_NAME_PRIMARY, // 7
+ };
+
+ private static final String[] PROJECTION_ALTERNATIVE = new String[] {
+ Phone._ID, // 0
+ Phone.TYPE, // 1
+ Phone.LABEL, // 2
+ Phone.NUMBER, // 3
+ Phone.CONTACT_ID, // 4
+ Phone.LOOKUP_KEY, // 5
+ Phone.PHOTO_ID, // 6
+ Phone.DISPLAY_NAME_ALTERNATIVE, // 7
+ };
+
+ public static final int PHONE_ID = 0;
+ public static final int PHONE_TYPE = 1;
+ public static final int PHONE_LABEL = 2;
+ public static final int PHONE_NUMBER = 3;
+ public static final int PHONE_CONTACT_ID = 4;
+ public static final int PHONE_LOOKUP_KEY = 5;
+ public static final int PHONE_PHOTO_ID = 6;
+ public static final int PHONE_DISPLAY_NAME = 7;
+ }
+
+ private final CharSequence mUnknownNameText;
+
+ private ContactListItemView.PhotoPosition mPhotoPosition;
+
+ private boolean mUseCallableUri;
+
+ public PhoneNumberListAdapter(Context context) {
+ super(context);
+ setDefaultFilterHeaderText(R.string.list_filter_phones);
+ mUnknownNameText = context.getText(android.R.string.unknownName);
+ }
+
+ protected CharSequence getUnknownNameText() {
+ return mUnknownNameText;
+ }
+
+ @Override
+ public void configureLoader(CursorLoader loader, long directoryId) {
+ if (directoryId != Directory.DEFAULT) {
+ Log.w(TAG, "PhoneNumberListAdapter is not ready for non-default directory ID ("
+ + "directoryId: " + directoryId + ")");
+ }
+
+ final Builder builder;
+ if (isSearchMode()) {
+ final Uri baseUri =
+ mUseCallableUri ? Callable.CONTENT_FILTER_URI : Phone.CONTENT_FILTER_URI;
+ builder = baseUri.buildUpon();
+ final String query = getQueryString();
+ if (TextUtils.isEmpty(query)) {
+ builder.appendPath("");
+ } else {
+ builder.appendPath(query); // Builder will encode the query
+ }
+ builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(directoryId));
+ } else {
+ final Uri baseUri = mUseCallableUri ? Callable.CONTENT_URI : Phone.CONTENT_URI;
+ builder = baseUri.buildUpon().appendQueryParameter(
+ ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT));
+ if (isSectionHeaderDisplayEnabled()) {
+ builder.appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true");
+ }
+ applyFilter(loader, builder, directoryId, getFilter());
+ }
+
+ // Remove duplicates when it is possible.
+ builder.appendQueryParameter(ContactsContract.REMOVE_DUPLICATE_ENTRIES, "true");
+ loader.setUri(builder.build());
+
+ // TODO a projection that includes the search snippet
+ if (getContactNameDisplayOrder() == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) {
+ loader.setProjection(PhoneQuery.PROJECTION_PRIMARY);
+ } else {
+ loader.setProjection(PhoneQuery.PROJECTION_ALTERNATIVE);
+ }
+
+ if (getSortOrder() == ContactsContract.Preferences.SORT_ORDER_PRIMARY) {
+ loader.setSortOrder(Phone.SORT_KEY_PRIMARY);
+ } else {
+ loader.setSortOrder(Phone.SORT_KEY_ALTERNATIVE);
+ }
+ }
+
+ /**
+ * Configure {@code loader} and {@code uriBuilder} according to {@code directoryId} and {@code
+ * filter}.
+ */
+ private void applyFilter(CursorLoader loader, Uri.Builder uriBuilder, long directoryId,
+ ContactListFilter filter) {
+ if (filter == null || directoryId != Directory.DEFAULT) {
+ return;
+ }
+
+ final StringBuilder selection = new StringBuilder();
+ final List<String> selectionArgs = new ArrayList<String>();
+
+ switch (filter.filterType) {
+ case ContactListFilter.FILTER_TYPE_CUSTOM: {
+ selection.append(Contacts.IN_VISIBLE_GROUP + "=1");
+ selection.append(" AND " + Contacts.HAS_PHONE_NUMBER + "=1");
+ break;
+ }
+ case ContactListFilter.FILTER_TYPE_ACCOUNT: {
+ filter.addAccountQueryParameterToUrl(uriBuilder);
+ break;
+ }
+ case ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS:
+ case ContactListFilter.FILTER_TYPE_DEFAULT:
+ break; // No selection needed.
+ case ContactListFilter.FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY:
+ break; // This adapter is always "phone only", so no selection needed either.
+ default:
+ Log.w(TAG, "Unsupported filter type came " +
+ "(type: " + filter.filterType + ", toString: " + filter + ")" +
+ " showing all contacts.");
+ // No selection.
+ break;
+ }
+ loader.setSelection(selection.toString());
+ loader.setSelectionArgs(selectionArgs.toArray(new String[0]));
+ }
+
+ @Override
+ public String getContactDisplayName(int position) {
+ return ((Cursor) getItem(position)).getString(PhoneQuery.PHONE_DISPLAY_NAME);
+ }
+
+ /**
+ * Builds a {@link Data#CONTENT_URI} for the given cursor position.
+ *
+ * @return Uri for the data. may be null if the cursor is not ready.
+ */
+ public Uri getDataUri(int position) {
+ Cursor cursor = ((Cursor)getItem(position));
+ if (cursor != null) {
+ long id = cursor.getLong(PhoneQuery.PHONE_ID);
+ return ContentUris.withAppendedId(Data.CONTENT_URI, id);
+ } else {
+ Log.w(TAG, "Cursor was null in getDataUri() call. Returning null instead.");
+ return null;
+ }
+ }
+
+ @Override
+ protected View newView(Context context, int partition, Cursor cursor, int position,
+ ViewGroup parent) {
+ final ContactListItemView view = new ContactListItemView(context, null);
+ view.setUnknownNameText(mUnknownNameText);
+ view.setQuickContactEnabled(isQuickContactEnabled());
+ view.setPhotoPosition(mPhotoPosition);
+ return view;
+ }
+
+ @Override
+ protected void bindView(View itemView, int partition, Cursor cursor, int position) {
+ ContactListItemView view = (ContactListItemView)itemView;
+
+ view.setHighlightedPrefix(isSearchMode() ? getUpperCaseQueryString() : null);
+
+ // Look at elements before and after this position, checking if contact IDs are same.
+ // If they have one same contact ID, it means they can be grouped.
+ //
+ // In one group, only the first entry will show its photo and its name, and the other
+ // entries in the group show just their data (e.g. phone number, email address).
+ cursor.moveToPosition(position);
+ boolean isFirstEntry = true;
+ boolean showBottomDivider = true;
+ final long currentContactId = cursor.getLong(PhoneQuery.PHONE_CONTACT_ID);
+ if (cursor.moveToPrevious() && !cursor.isBeforeFirst()) {
+ final long previousContactId = cursor.getLong(PhoneQuery.PHONE_CONTACT_ID);
+ if (currentContactId == previousContactId) {
+ isFirstEntry = false;
+ }
+ }
+ cursor.moveToPosition(position);
+ if (cursor.moveToNext() && !cursor.isAfterLast()) {
+ final long nextContactId = cursor.getLong(PhoneQuery.PHONE_CONTACT_ID);
+ if (currentContactId == nextContactId) {
+ // The following entry should be in the same group, which means we don't want a
+ // divider between them.
+ // TODO: we want a different divider than the divider between groups. Just hiding
+ // this divider won't be enough.
+ showBottomDivider = false;
+ }
+ }
+ cursor.moveToPosition(position);
+
+ bindSectionHeaderAndDivider(view, position);
+ if (isFirstEntry) {
+ bindName(view, cursor);
+ if (isQuickContactEnabled()) {
+ // No need for photo uri here, because we can not have directory results. If we
+ // ever do, we need to add photo uri to the query
+ bindQuickContact(view, partition, cursor, PhoneQuery.PHONE_PHOTO_ID, -1,
+ PhoneQuery.PHONE_CONTACT_ID, PhoneQuery.PHONE_LOOKUP_KEY);
+ } else {
+ bindPhoto(view, cursor);
+ }
+ } else {
+ unbindName(view);
+
+ view.removePhotoView(true, false);
+ }
+ bindPhoneNumber(view, cursor);
+ view.setDividerVisible(showBottomDivider);
+ }
+
+ protected void bindPhoneNumber(ContactListItemView view, Cursor cursor) {
+ CharSequence label = null;
+ if (!cursor.isNull(PhoneQuery.PHONE_TYPE)) {
+ final int type = cursor.getInt(PhoneQuery.PHONE_TYPE);
+ final String customLabel = cursor.getString(PhoneQuery.PHONE_LABEL);
+
+ // TODO cache
+ label = Phone.getTypeLabel(getContext().getResources(), type, customLabel);
+ }
+ view.setLabel(label);
+ view.showData(cursor, PhoneQuery.PHONE_NUMBER);
+ }
+
+ protected void bindSectionHeaderAndDivider(final ContactListItemView view, int position) {
+ if (isSectionHeaderDisplayEnabled()) {
+ Placement placement = getItemPlacementInSection(position);
+ view.setSectionHeader(placement.firstInSection ? placement.sectionHeader : null);
+ view.setDividerVisible(!placement.lastInSection);
+ } else {
+ view.setSectionHeader(null);
+ view.setDividerVisible(true);
+ }
+ }
+
+ protected void bindName(final ContactListItemView view, Cursor cursor) {
+ view.showDisplayName(cursor, PhoneQuery.PHONE_DISPLAY_NAME, getContactNameDisplayOrder());
+ // Note: we don't show phonetic names any more (see issue 5265330)
+ }
+
+ protected void unbindName(final ContactListItemView view) {
+ view.hideDisplayName();
+ }
+
+ protected void bindPhoto(final ContactListItemView view, Cursor cursor) {
+ long photoId = 0;
+ if (!cursor.isNull(PhoneQuery.PHONE_PHOTO_ID)) {
+ photoId = cursor.getLong(PhoneQuery.PHONE_PHOTO_ID);
+ }
+
+ getPhotoLoader().loadThumbnail(view.getPhotoView(), photoId, false);
+ }
+
+ public void setPhotoPosition(ContactListItemView.PhotoPosition photoPosition) {
+ mPhotoPosition = photoPosition;
+ }
+
+ public ContactListItemView.PhotoPosition getPhotoPosition() {
+ return mPhotoPosition;
+ }
+
+ public void setUseCallableUri(boolean useCallableUri) {
+ mUseCallableUri = useCallableUri;
+ }
+
+ public boolean usesCallableUri() {
+ return mUseCallableUri;
+ }
+}