ContactListItemView.java revision 9f0c1621718b382531cbebfe38907e6d3db6ceae
1d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng/*
2d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * Copyright (C) 2010 The Android Open Source Project
3d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng *
4d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * Licensed under the Apache License, Version 2.0 (the "License");
5d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * you may not use this file except in compliance with the License.
6d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * You may obtain a copy of the License at
7d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng *
8d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng *      http://www.apache.org/licenses/LICENSE-2.0
9d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng *
10d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * Unless required by applicable law or agreed to in writing, software
11d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * distributed under the License is distributed on an "AS IS" BASIS,
12d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * See the License for the specific language governing permissions and
14d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * limitations under the License.
15d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng */
16d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
17d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengpackage com.android.contacts.common.list;
18d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
19d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.content.Context;
20d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.content.res.ColorStateList;
21d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.content.res.TypedArray;
22d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.database.CharArrayBuffer;
23d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.database.Cursor;
24d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.graphics.Canvas;
25d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.graphics.Color;
26d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.graphics.Rect;
27d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.graphics.Typeface;
28d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.graphics.drawable.Drawable;
29d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.os.Bundle;
30d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.provider.ContactsContract;
31d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.provider.ContactsContract.Contacts;
32d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.text.Spannable;
33d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.text.SpannableString;
34d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.text.TextUtils;
35d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.text.TextUtils.TruncateAt;
36d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.util.AttributeSet;
37d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.util.TypedValue;
38d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.view.Gravity;
39d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.view.View;
40d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.view.ViewGroup;
41d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.widget.AbsListView.SelectionBoundsAdjuster;
42d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.widget.ImageView;
43d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.widget.ImageView.ScaleType;
44d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.widget.QuickContactBadge;
45d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.widget.TextView;
46d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
47d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport com.android.contacts.common.ContactPresenceIconUtil;
48d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport com.android.contacts.common.ContactStatusUtil;
49d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport com.android.contacts.common.R;
50d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport com.android.contacts.common.format.PrefixHighlighter;
51cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Chengimport com.android.contacts.common.util.SearchUtil;
5205897c8e016942e10f0ef6f0da02d339480d4748Chiao Chengimport com.google.common.collect.Lists;
5305897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng
5405897c8e016942e10f0ef6f0da02d339480d4748Chiao Chengimport java.util.ArrayList;
5505897c8e016942e10f0ef6f0da02d339480d4748Chiao Chengimport java.util.List;
569f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglioimport java.util.Locale;
5705897c8e016942e10f0ef6f0da02d339480d4748Chiao Chengimport java.util.regex.Matcher;
5805897c8e016942e10f0ef6f0da02d339480d4748Chiao Chengimport java.util.regex.Pattern;
59d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
60d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng/**
61d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * A custom view for an item in the contact list.
62d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * The view contains the contact's photo, a set of text views (for name, status, etc...) and
63d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * icons for presence and call.
64d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * The view uses no XML file for layout and all the measurements and layouts are done
65d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * in the onMeasure and onLayout methods.
66d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng *
67d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * The layout puts the contact's photo on the right side of the view, the call icon (if present)
68d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * to the left of the photo, the text lines are aligned to the left and the presence icon (if
69d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * present) is set to the left of the status line.
70d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng *
71d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * The layout also supports a header (used as a header of a group of contacts) that is above the
72d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * contact's data and a divider between contact view.
73d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng */
74d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
75d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengpublic class ContactListItemView extends ViewGroup
76d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        implements SelectionBoundsAdjuster {
77d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
78d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // Style values for layout and appearance
79d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // The initialized values are defaults if none is provided through xml.
80d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mPreferredHeight = 0;
81d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mGapBetweenImageAndText = 0;
82d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mGapBetweenLabelAndData = 0;
83d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mPresenceIconMargin = 4;
84d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mPresenceIconSize = 16;
85d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mHeaderTextColor = Color.BLACK;
86d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mHeaderTextIndent = 0;
87d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mHeaderTextSize = 12;
88d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mHeaderUnderlineHeight = 1;
89d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mHeaderUnderlineColor = 0;
90d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mCountViewTextSize = 12;
91d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mContactsCountTextColor = Color.BLACK;
92d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mTextIndent = 0;
93d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private Drawable mActivatedBackgroundDrawable;
94d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
95d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
96d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Used with {@link #mLabelView}, specifying the width ratio between label and data.
97d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
98d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mLabelViewWidthWeight = 3;
99d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
100d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Used with {@link #mDataView}, specifying the width ratio between label and data.
101d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
102d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mDataViewWidthWeight = 5;
103d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
104d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // Will be used with adjustListItemSelectionBounds().
105d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mSelectionBoundsMarginLeft;
106d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mSelectionBoundsMarginRight;
107d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
108d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // Horizontal divider between contact views.
109d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mHorizontalDividerVisible = true;
110d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private Drawable mHorizontalDividerDrawable;
111d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mHorizontalDividerHeight;
112d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
113d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
114d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Where to put contact photo. This affects the other Views' layout or look-and-feel.
1159f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio     *
1169f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio     * TODO: replace enum with int constants
117d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
118d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public enum PhotoPosition {
119d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        LEFT,
120d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        RIGHT
121d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1229f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio
1239f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio    static public final PhotoPosition getDefaultPhotoPosition(boolean opposite) {
1249f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        final Locale locale = Locale.getDefault();
1259f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        final int layoutDirection = TextUtils.getLayoutDirectionFromLocale(locale);
1269f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        switch (layoutDirection) {
1279f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            case View.LAYOUT_DIRECTION_RTL:
1289f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                return (opposite ? PhotoPosition.RIGHT : PhotoPosition.LEFT);
1299f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            case View.LAYOUT_DIRECTION_LTR:
1309f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            default:
1319f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                return (opposite ? PhotoPosition.LEFT : PhotoPosition.RIGHT);
1329f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        }
1339f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio    }
1349f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio
1359f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio    private PhotoPosition mPhotoPosition = getDefaultPhotoPosition(false /* normal/non opposite */);
136d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
137d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // Header layout data
138d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mHeaderVisible;
139d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private View mHeaderDivider;
140d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mHeaderBackgroundHeight = 30;
141d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mHeaderTextView;
142d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
143d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // The views inside the contact view
144d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mQuickContactEnabled = true;
145d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private QuickContactBadge mQuickContact;
146d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private ImageView mPhotoView;
147d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mNameTextView;
148d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mPhoneticNameTextView;
149d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mLabelView;
150d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mDataView;
151d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mSnippetView;
152d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mStatusView;
153d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mCountView;
154d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private ImageView mPresenceIcon;
155d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
156d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private ColorStateList mSecondaryTextColor;
157d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
158bd80fd64b9ff94c9ffbdb843beb4b363bb209463Chiao Cheng    private String mHighlightedPrefix;
159d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
160d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mDefaultPhotoViewSize = 0;
161d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
162d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Can be effective even when {@link #mPhotoView} is null, as we want to have horizontal padding
163d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * to align other data in this View.
164d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
165d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mPhotoViewWidth;
166d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
167d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Can be effective even when {@link #mPhotoView} is null, as we want to have vertical padding.
168d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
169d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mPhotoViewHeight;
170d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
171d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
172d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Only effective when {@link #mPhotoView} is null.
173d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * When true all the Views on the right side of the photo should have horizontal padding on
174d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * those left assuming there is a photo.
175d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
176d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mKeepHorizontalPaddingForPhotoView;
177d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
178d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Only effective when {@link #mPhotoView} is null.
179d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
180d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mKeepVerticalPaddingForPhotoView;
181d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
182d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
183d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * True when {@link #mPhotoViewWidth} and {@link #mPhotoViewHeight} are ready for being used.
184d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * False indicates those values should be updated before being used in position calculation.
185d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
186d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mPhotoViewWidthAndHeightAreReady = false;
187d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
188d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mNameTextViewHeight;
189d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mPhoneticNameTextViewHeight;
190d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mLabelViewHeight;
191d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mDataViewHeight;
192d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mSnippetTextViewHeight;
193d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mStatusTextViewHeight;
194d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
195d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // Holds Math.max(mLabelTextViewHeight, mDataViewHeight), assuming Label and Data share the
196d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // same row.
197d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mLabelAndDataViewMaxHeight;
198d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
199d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // TODO: some TextView fields are using CharArrayBuffer while some are not. Determine which is
200d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // more efficient for each case or in general, and simplify the whole implementation.
201d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // Note: if we're sure MARQUEE will be used every time, there's no reason to use
202d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // CharArrayBuffer, since MARQUEE requires Span and thus we need to copy characters inside the
203d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // buffer to Spannable once, while CharArrayBuffer is for directly applying char array to
204d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // TextView without any modification.
205d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private final CharArrayBuffer mDataBuffer = new CharArrayBuffer(128);
206d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private final CharArrayBuffer mPhoneticNameBuffer = new CharArrayBuffer(128);
207d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
208d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mActivatedStateSupported;
209d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
210d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private Rect mBoundsWithoutHeader = new Rect();
211d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
212d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /** A helper used to highlight a prefix in a text field. */
213d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private PrefixHighlighter mPrefixHighlighter;
214d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private CharSequence mUnknownNameText;
215d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
216d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public ContactListItemView(Context context) {
217d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        super(context);
218d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mContext = context;
219d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
220d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mPrefixHighlighter = new PrefixHighlighter(Color.GREEN);
221d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
222d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
223d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public ContactListItemView(Context context, AttributeSet attrs) {
224d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        super(context, attrs);
225d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mContext = context;
226d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
227d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Read all style values
228d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ContactListItemView);
229d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mPreferredHeight = a.getDimensionPixelSize(
230d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_list_item_height, mPreferredHeight);
231d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mActivatedBackgroundDrawable = a.getDrawable(
232d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_activated_background);
233d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mHorizontalDividerDrawable = a.getDrawable(
234d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_list_item_divider);
235d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
236d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mGapBetweenImageAndText = a.getDimensionPixelOffset(
237d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_list_item_gap_between_image_and_text,
238d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mGapBetweenImageAndText);
239d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mGapBetweenLabelAndData = a.getDimensionPixelOffset(
240d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_list_item_gap_between_label_and_data,
241d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mGapBetweenLabelAndData);
242d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mPresenceIconMargin = a.getDimensionPixelOffset(
243d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_list_item_presence_icon_margin,
244d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mPresenceIconMargin);
245d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mPresenceIconSize = a.getDimensionPixelOffset(
246d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_list_item_presence_icon_size, mPresenceIconSize);
247d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mDefaultPhotoViewSize = a.getDimensionPixelOffset(
248d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_list_item_photo_size, mDefaultPhotoViewSize);
249d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mHeaderTextIndent = a.getDimensionPixelOffset(
250d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_list_item_header_text_indent, mHeaderTextIndent);
251d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mHeaderTextColor = a.getColor(
252d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_list_item_header_text_color, mHeaderTextColor);
253d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mHeaderTextSize = a.getDimensionPixelSize(
254d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_list_item_header_text_size, mHeaderTextSize);
255d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mHeaderBackgroundHeight = a.getDimensionPixelSize(
256d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_list_item_header_height, mHeaderBackgroundHeight);
257d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mHeaderUnderlineHeight = a.getDimensionPixelSize(
258d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_list_item_header_underline_height,
259d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mHeaderUnderlineHeight);
260d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mHeaderUnderlineColor = a.getColor(
261d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_list_item_header_underline_color,
262d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mHeaderUnderlineColor);
263d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mTextIndent = a.getDimensionPixelOffset(
264d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_list_item_text_indent, mTextIndent);
265d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mCountViewTextSize = a.getDimensionPixelSize(
266d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_list_item_contacts_count_text_size,
267d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mCountViewTextSize);
268d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mContactsCountTextColor = a.getColor(
269d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_list_item_contacts_count_text_color,
270d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mContactsCountTextColor);
271d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mDataViewWidthWeight = a.getInteger(
272d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_list_item_data_width_weight, mDataViewWidthWeight);
273d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mLabelViewWidthWeight = a.getInteger(
274d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_list_item_label_width_weight,
275d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelViewWidthWeight);
276d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
2779f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        setPaddingRelative(
278d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                a.getDimensionPixelOffset(
279d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        R.styleable.ContactListItemView_list_item_padding_left, 0),
280d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                a.getDimensionPixelOffset(
281d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        R.styleable.ContactListItemView_list_item_padding_top, 0),
282d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                a.getDimensionPixelOffset(
283d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        R.styleable.ContactListItemView_list_item_padding_right, 0),
284d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                a.getDimensionPixelOffset(
285d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        R.styleable.ContactListItemView_list_item_padding_bottom, 0));
286d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
287d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int prefixHighlightColor = a.getColor(
288d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                R.styleable.ContactListItemView_list_item_prefix_highlight_color, Color.GREEN);
289d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mPrefixHighlighter = new PrefixHighlighter(prefixHighlightColor);
290d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        a.recycle();
291d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
292d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        a = getContext().obtainStyledAttributes(android.R.styleable.Theme);
293d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mSecondaryTextColor = a.getColorStateList(android.R.styleable.Theme_textColorSecondary);
294d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        a.recycle();
295d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
296d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mHorizontalDividerHeight = mHorizontalDividerDrawable.getIntrinsicHeight();
297d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
298d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mActivatedBackgroundDrawable != null) {
299d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mActivatedBackgroundDrawable.setCallback(this);
300d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
301d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
302d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
303d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setUnknownNameText(CharSequence unknownNameText) {
304d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mUnknownNameText = unknownNameText;
305d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
306d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
307d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setQuickContactEnabled(boolean flag) {
308d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mQuickContactEnabled = flag;
309d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
310d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
311d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
312d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
313d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // We will match parent's width and wrap content vertically, but make sure
314d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // height is no less than listPreferredItemHeight.
315d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int specWidth = resolveSize(0, widthMeasureSpec);
316d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int preferredHeight;
317d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mHorizontalDividerVisible) {
318d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            preferredHeight = mPreferredHeight + mHorizontalDividerHeight;
319d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
320d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            preferredHeight = mPreferredHeight;
321d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
322d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
323d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mNameTextViewHeight = 0;
324d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mPhoneticNameTextViewHeight = 0;
325d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mLabelViewHeight = 0;
326d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mDataViewHeight = 0;
327d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mLabelAndDataViewMaxHeight = 0;
328d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mSnippetTextViewHeight = 0;
329d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mStatusTextViewHeight = 0;
330d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
331d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        ensurePhotoViewSize();
332d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
333d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Width each TextView is able to use.
334d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int effectiveWidth;
335d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // All the other Views will honor the photo, so available width for them may be shrunk.
336d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mPhotoViewWidth > 0 || mKeepHorizontalPaddingForPhotoView) {
337d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            effectiveWidth = specWidth - getPaddingLeft() - getPaddingRight()
338d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    - (mPhotoViewWidth + mGapBetweenImageAndText);
339d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
340d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            effectiveWidth = specWidth - getPaddingLeft() - getPaddingRight();
341d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
342d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
343d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Go over all visible text views and measure actual width of each of them.
344d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Also calculate their heights to get the total height for this entire view.
345d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
346d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mNameTextView)) {
347d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Caculate width for name text - this parallels similar measurement in onLayout.
348d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            int nameTextWidth = effectiveWidth;
349d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mPhotoPosition != PhotoPosition.LEFT) {
350d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                nameTextWidth -= mTextIndent;
351d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
352d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView.measure(
353d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(nameTextWidth, MeasureSpec.EXACTLY),
354d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
355d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextViewHeight = mNameTextView.getMeasuredHeight();
356d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
357d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
358d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mPhoneticNameTextView)) {
359d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.measure(
360d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(effectiveWidth, MeasureSpec.EXACTLY),
361d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
362d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextViewHeight = mPhoneticNameTextView.getMeasuredHeight();
363d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
364d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
365d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // If both data (phone number/email address) and label (type like "MOBILE") are quite long,
366d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // we should ellipsize both using appropriate ratio.
367d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int dataWidth;
368d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int labelWidth;
369d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mDataView)) {
370d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (isVisible(mLabelView)) {
371d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                final int totalWidth = effectiveWidth - mGapBetweenLabelAndData;
372d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                dataWidth = ((totalWidth * mDataViewWidthWeight)
373d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        / (mDataViewWidthWeight + mLabelViewWidthWeight));
374d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                labelWidth = ((totalWidth * mLabelViewWidthWeight) /
375d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        (mDataViewWidthWeight + mLabelViewWidthWeight));
376d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            } else {
377d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                dataWidth = effectiveWidth;
378d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                labelWidth = 0;
379d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
380d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
381d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            dataWidth = 0;
382d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (isVisible(mLabelView)) {
383d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                labelWidth = effectiveWidth;
384d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            } else {
385d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                labelWidth = 0;
386d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
387d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
388d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
389d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mDataView)) {
390d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataView.measure(MeasureSpec.makeMeasureSpec(dataWidth, MeasureSpec.EXACTLY),
391d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
392d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataViewHeight = mDataView.getMeasuredHeight();
393d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
394d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
395d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mLabelView)) {
396d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // For performance reason we don't want AT_MOST usually, but when the picture is
397d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // on right, we need to use it anyway because mDataView is next to mLabelView.
398d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            final int mode = (mPhotoPosition == PhotoPosition.LEFT
399d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    ? MeasureSpec.EXACTLY : MeasureSpec.AT_MOST);
400d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mLabelView.measure(MeasureSpec.makeMeasureSpec(labelWidth, mode),
401d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
402d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mLabelViewHeight = mLabelView.getMeasuredHeight();
403d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
404d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mLabelAndDataViewMaxHeight = Math.max(mLabelViewHeight, mDataViewHeight);
405d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
406d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mSnippetView)) {
407d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.measure(
408d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(effectiveWidth, MeasureSpec.EXACTLY),
409d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
410d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetTextViewHeight = mSnippetView.getMeasuredHeight();
411d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
412d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
413d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Status view height is the biggest of the text view and the presence icon
414d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mPresenceIcon)) {
415d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPresenceIcon.measure(
416d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(mPresenceIconSize, MeasureSpec.EXACTLY),
417d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(mPresenceIconSize, MeasureSpec.EXACTLY));
418d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusTextViewHeight = mPresenceIcon.getMeasuredHeight();
419d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
420d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
421d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mStatusView)) {
422d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Presence and status are in a same row, so status will be affected by icon size.
423d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            final int statusWidth;
424d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (isVisible(mPresenceIcon)) {
425d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                statusWidth = (effectiveWidth - mPresenceIcon.getMeasuredWidth()
426d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        - mPresenceIconMargin);
427d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            } else {
428d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                statusWidth = effectiveWidth;
429d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
430d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView.measure(MeasureSpec.makeMeasureSpec(statusWidth, MeasureSpec.EXACTLY),
431d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
432d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusTextViewHeight =
433d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    Math.max(mStatusTextViewHeight, mStatusView.getMeasuredHeight());
434d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
435d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
436d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Calculate height including padding.
437d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int height = (mNameTextViewHeight + mPhoneticNameTextViewHeight +
438d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelAndDataViewMaxHeight +
439d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mSnippetTextViewHeight + mStatusTextViewHeight);
440d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
441d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Make sure the height is at least as high as the photo
442d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        height = Math.max(height, mPhotoViewHeight + getPaddingBottom() + getPaddingTop());
443d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
444d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Add horizontal divider height
445d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mHorizontalDividerVisible) {
446d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            height += mHorizontalDividerHeight;
447d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
448d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
449d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Make sure height is at least the preferred height
450d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        height = Math.max(height, preferredHeight);
451d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
452d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Add the height of the header if visible
453d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mHeaderVisible) {
4549f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            final int headerWidth = specWidth -
4559f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                    getPaddingLeft() - getPaddingRight() - mHeaderTextIndent;
456d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mHeaderTextView.measure(
4579f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                    MeasureSpec.makeMeasureSpec(headerWidth, MeasureSpec.EXACTLY),
458d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(mHeaderBackgroundHeight, MeasureSpec.EXACTLY));
459d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mCountView != null) {
460d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mCountView.measure(
4619f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        MeasureSpec.makeMeasureSpec(headerWidth, MeasureSpec.AT_MOST),
462d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        MeasureSpec.makeMeasureSpec(mHeaderBackgroundHeight, MeasureSpec.EXACTLY));
463d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
464d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mHeaderBackgroundHeight = Math.max(mHeaderBackgroundHeight,
465d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    mHeaderTextView.getMeasuredHeight());
466d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            height += (mHeaderBackgroundHeight + mHeaderUnderlineHeight);
467d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
468d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
469d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        setMeasuredDimension(specWidth, height);
470d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
471d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
472d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
473d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
474d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int height = bottom - top;
475d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int width = right - left;
476d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
477d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Determine the vertical bounds by laying out the header first.
478d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int topBound = 0;
479d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int bottomBound = height;
480d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int leftBound = getPaddingLeft();
481d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int rightBound = width - getPaddingRight();
482d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
4839f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        final boolean isLayoutRtl = isLayoutRtl();
48409f15e70e86d92ae0f4c15a726b777f170845a3cYorke Lee
485d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Put the header in the top of the contact view (Text + underline view)
486d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mHeaderVisible) {
4879f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            mHeaderTextView.layout(isLayoutRtl ? leftBound : leftBound + mHeaderTextIndent,
488d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    0,
4899f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                    isLayoutRtl ? rightBound - mHeaderTextIndent : rightBound,
490d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    mHeaderBackgroundHeight);
491d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mCountView != null) {
492d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mCountView.layout(rightBound - mCountView.getMeasuredWidth(),
493d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        0,
494d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        rightBound,
495d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        mHeaderBackgroundHeight);
496d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
497d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mHeaderDivider.layout(leftBound,
498d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    mHeaderBackgroundHeight,
499d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    rightBound,
500d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    mHeaderBackgroundHeight + mHeaderUnderlineHeight);
501d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            topBound += (mHeaderBackgroundHeight + mHeaderUnderlineHeight);
502d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
503d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
504d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Put horizontal divider at the bottom
505d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mHorizontalDividerVisible) {
506d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mHorizontalDividerDrawable.setBounds(
507d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    leftBound,
508d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    height - mHorizontalDividerHeight,
509d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    rightBound,
510d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    height);
511d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            bottomBound -= mHorizontalDividerHeight;
512d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
513d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
514d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mBoundsWithoutHeader.set(0, topBound, width, bottomBound);
515d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
516d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mActivatedStateSupported && isActivated()) {
517d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mActivatedBackgroundDrawable.setBounds(mBoundsWithoutHeader);
518d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
519d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
520d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final View photoView = mQuickContact != null ? mQuickContact : mPhotoView;
521d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mPhotoPosition == PhotoPosition.LEFT) {
522d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Photo is the left most view. All the other Views should on the right of the photo.
523d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (photoView != null) {
524d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                // Center the photo vertically
525d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                final int photoTop = topBound + (bottomBound - topBound - mPhotoViewHeight) / 2;
526d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                photoView.layout(
527d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        leftBound,
528d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        photoTop,
529d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        leftBound + mPhotoViewWidth,
530d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        photoTop + mPhotoViewHeight);
531d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                leftBound += mPhotoViewWidth + mGapBetweenImageAndText;
532d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            } else if (mKeepHorizontalPaddingForPhotoView) {
533d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                // Draw nothing but keep the padding.
534d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                leftBound += mPhotoViewWidth + mGapBetweenImageAndText;
535d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
536d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
537d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Photo is the right most view. Right bound should be adjusted that way.
538d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (photoView != null) {
539d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                // Center the photo vertically
540d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                final int photoTop = topBound + (bottomBound - topBound - mPhotoViewHeight) / 2;
541d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                photoView.layout(
542d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        rightBound - mPhotoViewWidth,
543d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        photoTop,
544d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        rightBound,
545d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        photoTop + mPhotoViewHeight);
546d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                rightBound -= (mPhotoViewWidth + mGapBetweenImageAndText);
5479f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            } else if (mKeepHorizontalPaddingForPhotoView) {
5489f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                // Draw nothing but keep the padding.
5499f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                rightBound -= (mPhotoViewWidth + mGapBetweenImageAndText);
550d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
551d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
552d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Add indent between left-most padding and texts.
553d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            leftBound += mTextIndent;
554d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
555d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
556d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Center text vertically
557d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int totalTextHeight = mNameTextViewHeight + mPhoneticNameTextViewHeight +
558d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelAndDataViewMaxHeight + mSnippetTextViewHeight + mStatusTextViewHeight;
559d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int textTopBound = (bottomBound + topBound - totalTextHeight) / 2;
560d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
561d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Layout all text view and presence icon
562d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Put name TextView first
563d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mNameTextView)) {
564d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView.layout(leftBound,
565d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    textTopBound,
566d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    rightBound,
567d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    textTopBound + mNameTextViewHeight);
568d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textTopBound += mNameTextViewHeight;
569d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
570d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
571d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Presence and status
5729f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        if (isLayoutRtl) {
5739f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            int statusRightBound = rightBound;
5749f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            if (isVisible(mPresenceIcon)) {
5759f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                int iconWidth = mPresenceIcon.getMeasuredWidth();
5769f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                mPresenceIcon.layout(
5779f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        rightBound - iconWidth,
5789f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound,
5799f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        rightBound,
5809f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound + mStatusTextViewHeight);
5819f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                statusRightBound -= (iconWidth + mPresenceIconMargin);
5829f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            }
583d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
5849f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            if (isVisible(mStatusView)) {
5859f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                mStatusView.layout(leftBound,
5869f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound,
5879f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        statusRightBound,
5889f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound + mStatusTextViewHeight);
5899f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            }
5909f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        } else {
5919f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            int statusLeftBound = leftBound;
5929f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            if (isVisible(mPresenceIcon)) {
5939f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                int iconWidth = mPresenceIcon.getMeasuredWidth();
5949f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                mPresenceIcon.layout(
5959f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        leftBound,
5969f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound,
5979f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        leftBound + iconWidth,
5989f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound + mStatusTextViewHeight);
5999f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                statusLeftBound += (iconWidth + mPresenceIconMargin);
6009f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            }
6019f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio
6029f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            if (isVisible(mStatusView)) {
6039f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                mStatusView.layout(statusLeftBound,
6049f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound,
6059f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        rightBound,
6069f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound + mStatusTextViewHeight);
6079f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            }
608d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
609d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
610d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mStatusView) || isVisible(mPresenceIcon)) {
611d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textTopBound += mStatusTextViewHeight;
612d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
613d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
614d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Rest of text views
615d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int dataLeftBound = leftBound;
616d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mPhoneticNameTextView)) {
617d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.layout(leftBound,
618d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    textTopBound,
619d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    rightBound,
620d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    textTopBound + mPhoneticNameTextViewHeight);
621d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textTopBound += mPhoneticNameTextViewHeight;
622d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
623d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
624d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Label and Data align bottom.
625d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mLabelView)) {
626d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mPhotoPosition == PhotoPosition.LEFT) {
627d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                // When photo is on left, label is placed on the right edge of the list item.
628d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelView.layout(rightBound - mLabelView.getMeasuredWidth(),
629d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        textTopBound + mLabelAndDataViewMaxHeight - mLabelViewHeight,
630d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        rightBound,
631d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        textTopBound + mLabelAndDataViewMaxHeight);
632d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                rightBound -= mLabelView.getMeasuredWidth();
633d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            } else {
634d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                // When photo is on right, label is placed on the left of data view.
635d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                dataLeftBound = leftBound + mLabelView.getMeasuredWidth();
636d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelView.layout(leftBound,
637d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        textTopBound + mLabelAndDataViewMaxHeight - mLabelViewHeight,
638d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        dataLeftBound,
639d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        textTopBound + mLabelAndDataViewMaxHeight);
640d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                dataLeftBound += mGapBetweenLabelAndData;
641d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
642d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
643d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
644d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mDataView)) {
645d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataView.layout(dataLeftBound,
646d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    textTopBound + mLabelAndDataViewMaxHeight - mDataViewHeight,
647d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    rightBound,
648d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    textTopBound + mLabelAndDataViewMaxHeight);
649d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
650d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mLabelView) || isVisible(mDataView)) {
651d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textTopBound += mLabelAndDataViewMaxHeight;
652d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
653d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
654d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mSnippetView)) {
655d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.layout(leftBound,
656d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    textTopBound,
657d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    rightBound,
658d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    textTopBound + mSnippetTextViewHeight);
659d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
660d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
661d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
662d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
663d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void adjustListItemSelectionBounds(Rect bounds) {
664d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        bounds.top += mBoundsWithoutHeader.top;
665d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        bounds.bottom = bounds.top + mBoundsWithoutHeader.height();
666d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        bounds.left += mSelectionBoundsMarginLeft;
667d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        bounds.right -= mSelectionBoundsMarginRight;
668d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
669d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
670d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected boolean isVisible(View view) {
671d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return view != null && view.getVisibility() == View.VISIBLE;
672d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
673d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
674d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
675d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Extracts width and height from the style
676d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
677d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private void ensurePhotoViewSize() {
678d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (!mPhotoViewWidthAndHeightAreReady) {
679d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoViewWidth = mPhotoViewHeight = getDefaultPhotoViewSize();
680d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (!mQuickContactEnabled && mPhotoView == null) {
681d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                if (!mKeepHorizontalPaddingForPhotoView) {
682d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    mPhotoViewWidth = 0;
683d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                }
684d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                if (!mKeepVerticalPaddingForPhotoView) {
685d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    mPhotoViewHeight = 0;
686d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                }
687d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
688d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
689d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoViewWidthAndHeightAreReady = true;
690d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
691d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
692d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
693d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected void setDefaultPhotoViewSize(int pixels) {
694d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mDefaultPhotoViewSize = pixels;
695d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
696d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
697d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected int getDefaultPhotoViewSize() {
698d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mDefaultPhotoViewSize;
699d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
700d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
701d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
702d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Gets a LayoutParam that corresponds to the default photo size.
703d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     *
704d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * @return A new LayoutParam.
705d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
706d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private LayoutParams getDefaultPhotoLayoutParams() {
707d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        LayoutParams params = generateDefaultLayoutParams();
708d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        params.width = getDefaultPhotoViewSize();
709d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        params.height = params.width;
710d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return params;
711d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
712d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
713d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
714d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected void drawableStateChanged() {
715d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        super.drawableStateChanged();
716d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mActivatedStateSupported) {
717d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mActivatedBackgroundDrawable.setState(getDrawableState());
718d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
719d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
720d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
721d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
722d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected boolean verifyDrawable(Drawable who) {
723d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return who == mActivatedBackgroundDrawable || super.verifyDrawable(who);
724d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
725d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
726d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
727d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void jumpDrawablesToCurrentState() {
728d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        super.jumpDrawablesToCurrentState();
729d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mActivatedStateSupported) {
730d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mActivatedBackgroundDrawable.jumpToCurrentState();
731d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
732d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
733d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
734d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
735d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void dispatchDraw(Canvas canvas) {
736d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mActivatedStateSupported && isActivated()) {
737d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mActivatedBackgroundDrawable.draw(canvas);
738d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
739d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mHorizontalDividerVisible) {
740d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mHorizontalDividerDrawable.draw(canvas);
741d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
742d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
743d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        super.dispatchDraw(canvas);
744d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
745d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
746d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
747d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Sets the flag that determines whether a divider should drawn at the bottom
748d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * of the view.
749d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
750d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setDividerVisible(boolean visible) {
751d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mHorizontalDividerVisible = visible;
752d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
753d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
754d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
755d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Sets section header or makes it invisible if the title is null.
756d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
757d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setSectionHeader(String title) {
758d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (!TextUtils.isEmpty(title)) {
759d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mHeaderTextView == null) {
760d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mHeaderTextView = new TextView(mContext);
761d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mHeaderTextView.setTextColor(mHeaderTextColor);
762d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mHeaderTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mHeaderTextSize);
763d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mHeaderTextView.setTypeface(mHeaderTextView.getTypeface(), Typeface.BOLD);
764d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mHeaderTextView.setGravity(Gravity.CENTER_VERTICAL);
7659f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                mHeaderTextView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
766d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                addView(mHeaderTextView);
767d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
768d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mHeaderDivider == null) {
769d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mHeaderDivider = new View(mContext);
770d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mHeaderDivider.setBackgroundColor(mHeaderUnderlineColor);
771d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                addView(mHeaderDivider);
772d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
773d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setMarqueeText(mHeaderTextView, title);
774d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mHeaderTextView.setVisibility(View.VISIBLE);
775d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mHeaderDivider.setVisibility(View.VISIBLE);
776d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mHeaderTextView.setAllCaps(true);
777d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mHeaderVisible = true;
778d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
779d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mHeaderTextView != null) {
780d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mHeaderTextView.setVisibility(View.GONE);
781d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
782d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mHeaderDivider != null) {
783d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mHeaderDivider.setVisibility(View.GONE);
784d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
785d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mHeaderVisible = false;
786d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
787d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
788d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
789d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
790d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the quick contact badge, creating it if necessary.
791d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
792d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public QuickContactBadge getQuickContact() {
793d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (!mQuickContactEnabled) {
794d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            throw new IllegalStateException("QuickContact is disabled for this view");
795d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
796d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mQuickContact == null) {
797d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mQuickContact = new QuickContactBadge(mContext);
798d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mQuickContact.setLayoutParams(getDefaultPhotoLayoutParams());
799d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mNameTextView != null) {
800d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mQuickContact.setContentDescription(mContext.getString(
801d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        R.string.description_quick_contact_for, mNameTextView.getText()));
802d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
803d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
804d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mQuickContact);
805d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoViewWidthAndHeightAreReady = false;
806d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
807d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mQuickContact;
808d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
809d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
810d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
811d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the photo view, creating it if necessary.
812d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
813d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public ImageView getPhotoView() {
814d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mPhotoView == null) {
815d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoView = new ImageView(mContext);
816d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoView.setLayoutParams(getDefaultPhotoLayoutParams());
817d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Quick contact style used above will set a background - remove it
818d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoView.setBackground(null);
819d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mPhotoView);
820d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoViewWidthAndHeightAreReady = false;
821d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
822d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mPhotoView;
823d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
824d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
825d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
826d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Removes the photo view.
827d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
828d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void removePhotoView() {
829d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        removePhotoView(false, true);
830d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
831d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
832d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
833d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Removes the photo view.
834d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     *
835d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * @param keepHorizontalPadding True means data on the right side will have
836d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     *            padding on left, pretending there is still a photo view.
837d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * @param keepVerticalPadding True means the View will have some height
838d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     *            enough for accommodating a photo view.
839d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
840d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void removePhotoView(boolean keepHorizontalPadding, boolean keepVerticalPadding) {
841d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mPhotoViewWidthAndHeightAreReady = false;
842d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mKeepHorizontalPaddingForPhotoView = keepHorizontalPadding;
843d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mKeepVerticalPaddingForPhotoView = keepVerticalPadding;
844d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mPhotoView != null) {
845d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            removeView(mPhotoView);
846d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoView = null;
847d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
848d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mQuickContact != null) {
849d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            removeView(mQuickContact);
850d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mQuickContact = null;
851d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
852d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
853d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
854d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
855d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Sets a word prefix that will be highlighted if encountered in fields like
856d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * name and search snippet.
857d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * <p>
858d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * NOTE: must be all upper-case
859d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
860bd80fd64b9ff94c9ffbdb843beb4b363bb209463Chiao Cheng    public void setHighlightedPrefix(String upperCasePrefix) {
861d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mHighlightedPrefix = upperCasePrefix;
862d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
863d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
864d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
865d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the text view for the contact name, creating it if necessary.
866d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
867d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public TextView getNameTextView() {
868d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mNameTextView == null) {
869d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView = new TextView(mContext);
870d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView.setSingleLine(true);
871d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView.setEllipsize(getTextEllipsis());
872d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView.setTextAppearance(mContext, android.R.style.TextAppearance_Medium);
873d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Manually call setActivated() since this view may be added after the first
874d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // setActivated() call toward this whole item view.
875d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView.setActivated(isActivated());
876d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView.setGravity(Gravity.CENTER_VERTICAL);
8779f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            mNameTextView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
8789f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            mNameTextView.setId(R.id.cliv_name_textview);
879d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mNameTextView);
880d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
881d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mNameTextView;
882d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
883d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
884d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
885d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Adds or updates a text view for the phonetic name.
886d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
887d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setPhoneticName(char[] text, int size) {
888d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (text == null || size == 0) {
889d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mPhoneticNameTextView != null) {
890d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mPhoneticNameTextView.setVisibility(View.GONE);
891d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
892d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
893d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            getPhoneticNameTextView();
894d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setMarqueeText(mPhoneticNameTextView, text, size);
895d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.setVisibility(VISIBLE);
896d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
897d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
898d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
899d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
900d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the text view for the phonetic name, creating it if necessary.
901d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
902d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public TextView getPhoneticNameTextView() {
903d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mPhoneticNameTextView == null) {
904d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView = new TextView(mContext);
905d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.setSingleLine(true);
906d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.setEllipsize(getTextEllipsis());
907d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.setTextAppearance(mContext, android.R.style.TextAppearance_Small);
908d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.setTypeface(mPhoneticNameTextView.getTypeface(), Typeface.BOLD);
909d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.setActivated(isActivated());
9109f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            mPhoneticNameTextView.setId(R.id.cliv_phoneticname_textview);
911d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mPhoneticNameTextView);
912d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
913d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mPhoneticNameTextView;
914d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
915d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
916d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
917d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Adds or updates a text view for the data label.
918d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
919d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setLabel(CharSequence text) {
920d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (TextUtils.isEmpty(text)) {
921d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mLabelView != null) {
922d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelView.setVisibility(View.GONE);
923d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
924d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
925d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            getLabelView();
926d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setMarqueeText(mLabelView, text);
927d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mLabelView.setVisibility(VISIBLE);
928d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
929d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
930d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
931d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
932d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the text view for the data label, creating it if necessary.
933d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
934d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public TextView getLabelView() {
935d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mLabelView == null) {
936d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mLabelView = new TextView(mContext);
937d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mLabelView.setSingleLine(true);
938d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mLabelView.setEllipsize(getTextEllipsis());
939d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mLabelView.setTextAppearance(mContext, android.R.style.TextAppearance_Small);
940d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mPhotoPosition == PhotoPosition.LEFT) {
941d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mCountViewTextSize);
942d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelView.setAllCaps(true);
9439f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                mLabelView.setGravity(Gravity.END);
944d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            } else {
945d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelView.setTypeface(mLabelView.getTypeface(), Typeface.BOLD);
946d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
947d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mLabelView.setActivated(isActivated());
9489f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            mLabelView.setId(R.id.cliv_label_textview);
949d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mLabelView);
950d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
951d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mLabelView;
952d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
953d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
954d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
955d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Adds or updates a text view for the data element.
956d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
9579f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio    public void setData(char[] text, int size, int dataColumnIndex) {
958d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (text == null || size == 0) {
959d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mDataView != null) {
960d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mDataView.setVisibility(View.GONE);
961d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
962d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
963d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            getDataView();
964d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setMarqueeText(mDataView, text, size);
965d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataView.setVisibility(VISIBLE);
9669f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            // Check if this is a phone number. This code works also for the legacy phone number
9679f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            // coming from LegacyPhoneNumberListAdapter.PHONE_NUMBER_COLUMN_INDEX because they are
9689f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            // the exact same constant value (3)
9699f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            if (dataColumnIndex == PhoneNumberListAdapter.PhoneQuery.PHONE_NUMBER) {
9709f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                // We have a phone number as "mDataView" so make it always LTR and VIEW_START
9719f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                mDataView.setTextDirection(View.TEXT_DIRECTION_LTR);
9729f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                mDataView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
9739f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            }
974d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
975d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
976d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
977d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private void setMarqueeText(TextView textView, char[] text, int size) {
978d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (getTextEllipsis() == TruncateAt.MARQUEE) {
979d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setMarqueeText(textView, new String(text, 0, size));
980d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
981d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textView.setText(text, 0, size);
982d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
983d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
984d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
985d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private void setMarqueeText(TextView textView, CharSequence text) {
986d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (getTextEllipsis() == TruncateAt.MARQUEE) {
987d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // To show MARQUEE correctly (with END effect during non-active state), we need
988d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // to build Spanned with MARQUEE in addition to TextView's ellipsize setting.
989d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            final SpannableString spannable = new SpannableString(text);
990d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            spannable.setSpan(TruncateAt.MARQUEE, 0, spannable.length(),
991d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
992d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textView.setText(spannable);
993d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
994d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textView.setText(text);
995d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
996d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
997d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
998d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
999d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the text view for the data text, creating it if necessary.
1000d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1001d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public TextView getDataView() {
1002d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mDataView == null) {
1003d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataView = new TextView(mContext);
1004d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataView.setSingleLine(true);
1005d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataView.setEllipsize(getTextEllipsis());
1006d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataView.setTextAppearance(mContext, android.R.style.TextAppearance_Small);
1007d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataView.setActivated(isActivated());
10089f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            mDataView.setId(R.id.cliv_data_view);
1009d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mDataView);
1010d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1011d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mDataView;
1012d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1013d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1014d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1015d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Adds or updates a text view for the search snippet.
1016d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1017d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setSnippet(String text) {
1018d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (TextUtils.isEmpty(text)) {
1019d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mSnippetView != null) {
1020d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mSnippetView.setVisibility(View.GONE);
1021d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1022d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1023d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPrefixHighlighter.setText(getSnippetView(), text, mHighlightedPrefix);
1024d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.setVisibility(VISIBLE);
1025d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1026d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1027d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1028d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1029d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the text view for the search snippet, creating it if necessary.
1030d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1031d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public TextView getSnippetView() {
1032d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mSnippetView == null) {
1033d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView = new TextView(mContext);
1034d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.setSingleLine(true);
1035d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.setEllipsize(getTextEllipsis());
1036d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.setTextAppearance(mContext, android.R.style.TextAppearance_Small);
1037d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.setTypeface(mSnippetView.getTypeface(), Typeface.BOLD);
1038d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.setActivated(isActivated());
1039d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mSnippetView);
1040d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1041d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mSnippetView;
1042d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1043d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1044d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1045d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the text view for the status, creating it if necessary.
1046d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1047d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public TextView getStatusView() {
1048d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mStatusView == null) {
1049d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView = new TextView(mContext);
1050d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView.setSingleLine(true);
1051d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView.setEllipsize(getTextEllipsis());
1052d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView.setTextAppearance(mContext, android.R.style.TextAppearance_Small);
1053d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView.setTextColor(mSecondaryTextColor);
1054d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView.setActivated(isActivated());
10559f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            mStatusView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
1056d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mStatusView);
1057d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1058d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mStatusView;
1059d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1060d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1061d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1062d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the text view for the contacts count, creating it if necessary.
1063d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1064d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public TextView getCountView() {
1065d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mCountView == null) {
1066d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mCountView = new TextView(mContext);
1067d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mCountView.setSingleLine(true);
1068d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mCountView.setEllipsize(getTextEllipsis());
1069d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mCountView.setTextAppearance(mContext, android.R.style.TextAppearance_Medium);
1070d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mCountView.setTextColor(R.color.contact_count_text_color);
1071d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mCountView);
1072d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1073d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mCountView;
1074d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1075d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1076d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1077d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Adds or updates a text view for the contacts count.
1078d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1079d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setCountView(CharSequence text) {
1080d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (TextUtils.isEmpty(text)) {
1081d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mCountView != null) {
1082d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mCountView.setVisibility(View.GONE);
1083d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1084d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1085d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            getCountView();
1086d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setMarqueeText(mCountView, text);
1087d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mCountView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mCountViewTextSize);
1088d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mCountView.setGravity(Gravity.CENTER_VERTICAL);
1089d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mCountView.setTextColor(mContactsCountTextColor);
1090d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mCountView.setVisibility(VISIBLE);
1091d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1092d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1093d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1094d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1095d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Adds or updates a text view for the status.
1096d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1097d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setStatus(CharSequence text) {
1098d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (TextUtils.isEmpty(text)) {
1099d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mStatusView != null) {
1100d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mStatusView.setVisibility(View.GONE);
1101d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1102d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1103d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            getStatusView();
1104d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setMarqueeText(mStatusView, text);
1105d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView.setVisibility(VISIBLE);
1106d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1107d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1108d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1109d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1110d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Adds or updates the presence icon view.
1111d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1112d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setPresence(Drawable icon) {
1113d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (icon != null) {
1114d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mPresenceIcon == null) {
1115d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mPresenceIcon = new ImageView(mContext);
1116d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                addView(mPresenceIcon);
1117d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1118d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPresenceIcon.setImageDrawable(icon);
1119d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPresenceIcon.setScaleType(ScaleType.CENTER);
1120d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPresenceIcon.setVisibility(View.VISIBLE);
1121d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1122d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mPresenceIcon != null) {
1123d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mPresenceIcon.setVisibility(View.GONE);
1124d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1125d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1126d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1127d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1128d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TruncateAt getTextEllipsis() {
1129d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return TruncateAt.MARQUEE;
1130d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1131d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1132d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void showDisplayName(Cursor cursor, int nameColumnIndex, int displayOrder) {
1133d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        CharSequence name = cursor.getString(nameColumnIndex);
1134d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (!TextUtils.isEmpty(name)) {
1135d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            name = mPrefixHighlighter.apply(name, mHighlightedPrefix);
1136d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1137d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            name = mUnknownNameText;
1138d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1139d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        setMarqueeText(getNameTextView(), name);
1140d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1141d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Since the quick contact content description is derived from the display name and there is
1142d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // no guarantee that when the quick contact is initialized the display name is already set,
1143d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // do it here too.
1144d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mQuickContact != null) {
1145d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mQuickContact.setContentDescription(mContext.getString(
1146d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    R.string.description_quick_contact_for, mNameTextView.getText()));
1147d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1148d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1149d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1150d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void hideDisplayName() {
1151d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mNameTextView != null) {
1152d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            removeView(mNameTextView);
1153d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView = null;
1154d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1155d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1156d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1157d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void showPhoneticName(Cursor cursor, int phoneticNameColumnIndex) {
1158d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        cursor.copyStringToBuffer(phoneticNameColumnIndex, mPhoneticNameBuffer);
1159d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int phoneticNameSize = mPhoneticNameBuffer.sizeCopied;
1160d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (phoneticNameSize != 0) {
1161d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setPhoneticName(mPhoneticNameBuffer.data, phoneticNameSize);
1162d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1163d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setPhoneticName(null, 0);
1164d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1165d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1166d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1167d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void hidePhoneticName() {
1168d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mPhoneticNameTextView != null) {
1169d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            removeView(mPhoneticNameTextView);
1170d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView = null;
1171d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1172d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1173d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1174d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1175d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Sets the proper icon (star or presence or nothing) and/or status message.
1176d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1177d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void showPresenceAndStatusMessage(Cursor cursor, int presenceColumnIndex,
1178d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            int contactStatusColumnIndex) {
1179d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        Drawable icon = null;
1180d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int presence = 0;
1181d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (!cursor.isNull(presenceColumnIndex)) {
1182d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            presence = cursor.getInt(presenceColumnIndex);
1183d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            icon = ContactPresenceIconUtil.getPresenceIcon(getContext(), presence);
1184d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1185d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        setPresence(icon);
1186d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1187d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        String statusMessage = null;
1188d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (contactStatusColumnIndex != 0 && !cursor.isNull(contactStatusColumnIndex)) {
1189d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            statusMessage = cursor.getString(contactStatusColumnIndex);
1190d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1191d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // If there is no status message from the contact, but there was a presence value, then use
1192d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // the default status message string
1193d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (statusMessage == null && presence != 0) {
1194d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            statusMessage = ContactStatusUtil.getStatusString(getContext(), presence);
1195d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1196d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        setStatus(statusMessage);
1197d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1198d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1199d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1200d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Shows search snippet.
1201d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1202d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void showSnippet(Cursor cursor, int summarySnippetColumnIndex) {
1203d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (cursor.getColumnCount() <= summarySnippetColumnIndex) {
1204d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setSnippet(null);
1205d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            return;
1206d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1207d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
120805897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        String snippet = cursor.getString(summarySnippetColumnIndex);
1209cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1210d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Do client side snippeting if provider didn't do it
121105897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        final Bundle extras = cursor.getExtras();
1212d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (extras.getBoolean(ContactsContract.DEFERRED_SNIPPETING)) {
1213d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
121405897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng            final String query = extras.getString(ContactsContract.DEFERRED_SNIPPETING_QUERY);
1215cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1216cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            String displayName = null;
1217cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            int displayNameIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
1218cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            if (displayNameIndex >= 0) {
1219cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                displayName = cursor.getString(displayNameIndex);
122005897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng            }
1221cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1222cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            snippet = updateSnippet(snippet, query, displayName);
1223cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
122405897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        } else {
122505897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng            if (snippet != null) {
122605897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                int from = 0;
122705897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                int to = snippet.length();
122805897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                int start = snippet.indexOf(DefaultContactListAdapter.SNIPPET_START_MATCH);
122905897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                if (start == -1) {
123005897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    snippet = null;
123105897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                } else {
123205897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    int firstNl = snippet.lastIndexOf('\n', start);
123305897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    if (firstNl != -1) {
123405897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        from = firstNl + 1;
123505897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    }
123605897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    int end = snippet.lastIndexOf(DefaultContactListAdapter.SNIPPET_END_MATCH);
123705897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    if (end != -1) {
123805897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        int lastNl = snippet.indexOf('\n', end);
123905897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        if (lastNl != -1) {
124005897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                            to = lastNl;
124105897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        }
124205897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    }
1243d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
124405897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    StringBuilder sb = new StringBuilder();
124505897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    for (int i = from; i < to; i++) {
124605897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        char c = snippet.charAt(i);
124705897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        if (c != DefaultContactListAdapter.SNIPPET_START_MATCH &&
124805897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                                c != DefaultContactListAdapter.SNIPPET_END_MATCH) {
124905897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                            sb.append(c);
125005897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        }
1251d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    }
125205897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    snippet = sb.toString();
1253d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                }
1254d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1255d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1256cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1257d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        setSnippet(snippet);
1258d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1259d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1260cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng    /**
1261cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     * Used for deferred snippets from the database. The contents come back as large strings which
1262cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     * need to be extracted for display.
1263cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     *
1264cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     * @param snippet The snippet from the database.
1265cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     * @param query The search query substring.
1266cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     * @param displayName The contact display name.
1267cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     * @return The proper snippet to display.
1268cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     */
1269cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng    private String updateSnippet(String snippet, String query, String displayName) {
1270cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1271cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        if (TextUtils.isEmpty(snippet) || TextUtils.isEmpty(query)) {
1272cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            return null;
1273cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1274cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        query = SearchUtil.cleanStartAndEndOfSearchQuery(query.toLowerCase());
1275cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1276cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // If the display name already contains the query term, return empty - snippets should
1277cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // not be needed in that case.
1278cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        if (!TextUtils.isEmpty(displayName)) {
1279cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            final String lowerDisplayName = displayName.toLowerCase();
1280cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            final List<String> nameTokens = split(lowerDisplayName);
1281cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            for (String nameToken : nameTokens) {
1282cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                if (nameToken.startsWith(query)) {
1283cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                    return null;
1284cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                }
1285cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            }
1286cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1287cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1288cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // The snippet may contain multiple data lines.
1289cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Show the first line that matches the query.
1290cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        final SearchUtil.MatchedLine matched = SearchUtil.findMatchingLine(snippet, query);
1291cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1292cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        if (matched != null && matched.line != null) {
1293cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            // Tokenize for long strings since the match may be at the end of it.
1294cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            // Skip this part for short strings since the whole string will be displayed.
1295cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            // Most contact strings are short so the snippetize method will be called infrequently.
1296cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            final int lengthThreshold = getResources().getInteger(
1297cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                    R.integer.snippet_length_before_tokenize);
1298cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            if (matched.line.length() > lengthThreshold) {
1299cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                return snippetize(matched.line, matched.startIndex, lengthThreshold);
1300cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            } else {
1301cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                return matched.line;
1302cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            }
1303cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1304cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1305cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // No match found.
1306cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        return null;
1307cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng    }
1308cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1309cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng    private String snippetize(String line, int matchIndex, int maxLength) {
1310cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Show up to maxLength characters. But we only show full tokens so show the last full token
1311cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // up to maxLength characters. So as many starting tokens as possible before trying ending
1312cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // tokens.
1313cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        int remainingLength = maxLength;
1314cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        int tempRemainingLength = remainingLength;
1315cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1316cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Start the end token after the matched query.
1317cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        int index = matchIndex;
1318cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        int endTokenIndex = index;
1319cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1320cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Find the match token first.
1321cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        while (index < line.length()) {
1322cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            if (!Character.isLetterOrDigit(line.charAt(index))) {
1323cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                endTokenIndex = index;
1324cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                remainingLength = tempRemainingLength;
1325cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                break;
1326cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            }
1327cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            tempRemainingLength--;
1328cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            index++;
1329cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1330cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1331cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Find as much content before the match.
1332cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        index = matchIndex - 1;
1333cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        tempRemainingLength = remainingLength;
1334cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        int startTokenIndex = matchIndex;
1335cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        while (index > -1 && tempRemainingLength > 0) {
1336cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            if (!Character.isLetterOrDigit(line.charAt(index))) {
1337cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                startTokenIndex = index;
1338cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                remainingLength = tempRemainingLength;
1339cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            }
1340cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            tempRemainingLength--;
1341cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            index--;
1342cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1343cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1344cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        index = endTokenIndex;
1345cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        tempRemainingLength = remainingLength;
1346cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Find remaining content at after match.
1347cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        while (index < line.length() && tempRemainingLength > 0) {
1348cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            if (!Character.isLetterOrDigit(line.charAt(index))) {
1349cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                endTokenIndex = index;
1350cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            }
1351cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            tempRemainingLength--;
1352cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            index++;
1353cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1354cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Append ellipse if there is content before or after.
1355cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        final StringBuilder sb = new StringBuilder();
1356cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        if (startTokenIndex > 0) {
1357cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            sb.append("...");
1358cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1359cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        sb.append(line.substring(startTokenIndex, endTokenIndex));
1360cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        if (endTokenIndex < line.length()) {
1361cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            sb.append("...");
1362cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1363cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        return sb.toString();
1364cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng    }
1365cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
136605897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng    private static final Pattern SPLIT_PATTERN = Pattern.compile(
136705897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng            "([\\w-\\.]+)@((?:[\\w]+\\.)+)([a-zA-Z]{2,4})|[\\w]+");
136805897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng
136905897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng    /**
137005897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     * Helper method for splitting a string into tokens.  The lists passed in are populated with
137105897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     * the
137205897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     * tokens and offsets into the content of each token.  The tokenization function parses e-mail
137305897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     * addresses as a single token; otherwise it splits on any non-alphanumeric character.
137405897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     *
137505897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     * @param content Content to split.
137605897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     * @return List of token strings.
137705897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     */
137805897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng    private static List<String> split(String content) {
137905897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        final Matcher matcher = SPLIT_PATTERN.matcher(content);
138005897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        final ArrayList<String> tokens = Lists.newArrayList();
138105897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        while (matcher.find()) {
138205897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng            tokens.add(matcher.group());
138305897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        }
138405897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        return tokens;
138505897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng    }
138605897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng
1387d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1388d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Shows data element (e.g. phone number).
1389d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1390d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void showData(Cursor cursor, int dataColumnIndex) {
1391d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        cursor.copyStringToBuffer(dataColumnIndex, mDataBuffer);
13929f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        setData(mDataBuffer.data, mDataBuffer.sizeCopied, dataColumnIndex);
1393d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1394d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1395d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setActivatedStateSupported(boolean flag) {
1396d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        this.mActivatedStateSupported = flag;
1397d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1398d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1399d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
1400d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void requestLayout() {
1401d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // We will assume that once measured this will not need to resize
1402d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // itself, so there is no need to pass the layout request to the parent
1403d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // view (ListView).
1404d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        forceLayout();
1405d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1406d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1407d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setPhotoPosition(PhotoPosition photoPosition) {
1408d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mPhotoPosition = photoPosition;
1409d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1410d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1411d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public PhotoPosition getPhotoPosition() {
1412d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mPhotoPosition;
1413d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1414d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1415d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1416d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Specifies left and right margin for selection bounds. See also
1417d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * {@link #adjustListItemSelectionBounds(Rect)}.
1418d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1419d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setSelectionBoundsHorizontalMargin(int left, int right) {
1420d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mSelectionBoundsMarginLeft = left;
1421d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mSelectionBoundsMarginRight = right;
1422d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1423d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng}
1424