ContactListItemView.java revision 3181b8ffaa6af370268acee97903e98a6b94138f
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;
2558a793ee1253f8f46dd7f754a51f61a6bbcdce60Andrew Leeimport 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;
323181b8ffaa6af370268acee97903e98a6b94138fWenyi Wangimport android.support.v4.content.ContextCompat;
33941090ea5f2cd169038bd9f6c2811d6bc12db6a5Brian Attwellimport android.telephony.PhoneNumberUtils;
34d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.text.Spannable;
35d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.text.SpannableString;
36d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.text.TextUtils;
37d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.text.TextUtils.TruncateAt;
38d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.util.AttributeSet;
393bc19a3bb1ed23b03352fff6de69a89e763a315eSai Cheemalapatiimport android.util.TypedValue;
40d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.view.Gravity;
4110349f190691f802b8935175dbf38bff74a8a703Yorke Leeimport android.view.MotionEvent;
42d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.view.View;
43d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.view.ViewGroup;
44d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.widget.AbsListView.SelectionBoundsAdjuster;
4508901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwellimport android.widget.CheckBox;
46d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.widget.ImageView;
47d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.widget.ImageView.ScaleType;
48d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.widget.QuickContactBadge;
49d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.widget.TextView;
50d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
51d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport com.android.contacts.common.ContactPresenceIconUtil;
52d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport com.android.contacts.common.ContactStatusUtil;
53d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport com.android.contacts.common.R;
54a81953a2b1818066ef5e44817f374ac288bab343Christine Chenimport com.android.contacts.common.format.TextHighlighter;
55d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jangimport com.android.contacts.common.util.ContactDisplayUtils;
56cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Chengimport com.android.contacts.common.util.SearchUtil;
57864c67691b5a0169b5cbb91469d67d93e24ad9ebYorke Leeimport com.android.contacts.common.util.ViewUtil;
58864c67691b5a0169b5cbb91469d67d93e24ad9ebYorke Lee
5905897c8e016942e10f0ef6f0da02d339480d4748Chiao Chengimport com.google.common.collect.Lists;
6005897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng
6105897c8e016942e10f0ef6f0da02d339480d4748Chiao Chengimport java.util.ArrayList;
6205897c8e016942e10f0ef6f0da02d339480d4748Chiao Chengimport java.util.List;
639f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglioimport java.util.Locale;
6405897c8e016942e10f0ef6f0da02d339480d4748Chiao Chengimport java.util.regex.Matcher;
6505897c8e016942e10f0ef6f0da02d339480d4748Chiao Chengimport java.util.regex.Pattern;
66d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
67d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng/**
68d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * A custom view for an item in the contact list.
69d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * The view contains the contact's photo, a set of text views (for name, status, etc...) and
70d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * icons for presence and call.
71d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * The view uses no XML file for layout and all the measurements and layouts are done
72d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * in the onMeasure and onLayout methods.
73d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng *
74d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * The layout puts the contact's photo on the right side of the view, the call icon (if present)
75d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * to the left of the photo, the text lines are aligned to the left and the presence icon (if
76d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * present) is set to the left of the status line.
77d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng *
78d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * The layout also supports a header (used as a header of a group of contacts) that is above the
79d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * contact's data and a divider between contact view.
80d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng */
81d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
82d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengpublic class ContactListItemView extends ViewGroup
83d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        implements SelectionBoundsAdjuster {
84d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
85d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // Style values for layout and appearance
86d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // The initialized values are defaults if none is provided through xml.
87d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mPreferredHeight = 0;
88d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mGapBetweenImageAndText = 0;
89d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mGapBetweenLabelAndData = 0;
90d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mPresenceIconMargin = 4;
91d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mPresenceIconSize = 16;
92d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mTextIndent = 0;
937961175eb7b8b8d6f990bd8e510f59fe48c5ef4bAndrew Lee    private int mTextOffsetTop;
943bc19a3bb1ed23b03352fff6de69a89e763a315eSai Cheemalapati    private int mNameTextViewTextSize;
951f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee    private int mHeaderWidth;
96d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private Drawable mActivatedBackgroundDrawable;
97d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
98f7a205fdcb17161c454bee673cc2fce5b23d0760Sai Cheemalapati    // Set in onLayout. Represent left and right position of the View on the screen.
99f7a205fdcb17161c454bee673cc2fce5b23d0760Sai Cheemalapati    private int mLeftOffset;
100f7a205fdcb17161c454bee673cc2fce5b23d0760Sai Cheemalapati    private int mRightOffset;
101f7a205fdcb17161c454bee673cc2fce5b23d0760Sai Cheemalapati
102d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
103d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Used with {@link #mLabelView}, specifying the width ratio between label and data.
104d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
105d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mLabelViewWidthWeight = 3;
106d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
107d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Used with {@link #mDataView}, specifying the width ratio between label and data.
108d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
109d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mDataViewWidthWeight = 5;
110d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
111f99a990be713ed35afe64ba8133c5428816390c6Christine Chen    protected static class HighlightSequence {
112f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        private final int start;
113f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        private final int end;
114f99a990be713ed35afe64ba8133c5428816390c6Christine Chen
115f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        HighlightSequence(int start, int end) {
116f99a990be713ed35afe64ba8133c5428816390c6Christine Chen            this.start = start;
117f99a990be713ed35afe64ba8133c5428816390c6Christine Chen            this.end = end;
118f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        }
119f99a990be713ed35afe64ba8133c5428816390c6Christine Chen    }
120f99a990be713ed35afe64ba8133c5428816390c6Christine Chen
121f99a990be713ed35afe64ba8133c5428816390c6Christine Chen    private ArrayList<HighlightSequence> mNameHighlightSequence;
122f99a990be713ed35afe64ba8133c5428816390c6Christine Chen    private ArrayList<HighlightSequence> mNumberHighlightSequence;
123a81953a2b1818066ef5e44817f374ac288bab343Christine Chen
124a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    // Highlighting prefix for names.
125a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    private String mHighlightedPrefix;
126a81953a2b1818066ef5e44817f374ac288bab343Christine Chen
127d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
128d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Where to put contact photo. This affects the other Views' layout or look-and-feel.
1299f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio     *
1309f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio     * TODO: replace enum with int constants
131d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
132d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public enum PhotoPosition {
133d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        LEFT,
134d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        RIGHT
135d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1369f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio
1379f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio    static public final PhotoPosition getDefaultPhotoPosition(boolean opposite) {
1389f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        final Locale locale = Locale.getDefault();
1399f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        final int layoutDirection = TextUtils.getLayoutDirectionFromLocale(locale);
1409f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        switch (layoutDirection) {
1419f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            case View.LAYOUT_DIRECTION_RTL:
142a9950433dc469d24b314204075a6250d2410e01bAndrew Lee                return (opposite ? PhotoPosition.LEFT : PhotoPosition.RIGHT);
1439f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            case View.LAYOUT_DIRECTION_LTR:
1449f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            default:
145a9950433dc469d24b314204075a6250d2410e01bAndrew Lee                return (opposite ? PhotoPosition.RIGHT : PhotoPosition.LEFT);
1469f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        }
1479f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio    }
1489f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio
1499f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio    private PhotoPosition mPhotoPosition = getDefaultPhotoPosition(false /* normal/non opposite */);
150d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
151d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // Header layout data
152d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mHeaderTextView;
1531f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee    private boolean mIsSectionHeaderEnabled;
154d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
155d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // The views inside the contact view
156d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mQuickContactEnabled = true;
157d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private QuickContactBadge mQuickContact;
158d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private ImageView mPhotoView;
159d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mNameTextView;
160d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mPhoneticNameTextView;
161d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mLabelView;
162d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mDataView;
163d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mSnippetView;
164d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mStatusView;
165d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private ImageView mPresenceIcon;
16608901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell    private CheckBox mCheckBox;
167d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
168d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private ColorStateList mSecondaryTextColor;
169d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
170a81953a2b1818066ef5e44817f374ac288bab343Christine Chen
171d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
172d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mDefaultPhotoViewSize = 0;
173d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
174d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Can be effective even when {@link #mPhotoView} is null, as we want to have horizontal padding
175d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * to align other data in this View.
176d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
177d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mPhotoViewWidth;
178d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
179d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Can be effective even when {@link #mPhotoView} is null, as we want to have vertical padding.
180d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
181d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mPhotoViewHeight;
182d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
183d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
184d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Only effective when {@link #mPhotoView} is null.
185d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * When true all the Views on the right side of the photo should have horizontal padding on
186d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * those left assuming there is a photo.
187d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
188d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mKeepHorizontalPaddingForPhotoView;
189d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
190d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Only effective when {@link #mPhotoView} is null.
191d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
192d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mKeepVerticalPaddingForPhotoView;
193d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
194d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
195d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * True when {@link #mPhotoViewWidth} and {@link #mPhotoViewHeight} are ready for being used.
196d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * False indicates those values should be updated before being used in position calculation.
197d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
198d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mPhotoViewWidthAndHeightAreReady = false;
199d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
200d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mNameTextViewHeight;
20158a793ee1253f8f46dd7f754a51f61a6bbcdce60Andrew Lee    private int mNameTextViewTextColor = Color.BLACK;
202d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mPhoneticNameTextViewHeight;
203d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mLabelViewHeight;
204d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mDataViewHeight;
205d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mSnippetTextViewHeight;
206d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mStatusTextViewHeight;
20708901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell    private int mCheckBoxHeight;
20808901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell    private int mCheckBoxWidth;
209d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
210d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // Holds Math.max(mLabelTextViewHeight, mDataViewHeight), assuming Label and Data share the
211d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // same row.
212d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mLabelAndDataViewMaxHeight;
213d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
214d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // TODO: some TextView fields are using CharArrayBuffer while some are not. Determine which is
215d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // more efficient for each case or in general, and simplify the whole implementation.
216d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // Note: if we're sure MARQUEE will be used every time, there's no reason to use
217d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // CharArrayBuffer, since MARQUEE requires Span and thus we need to copy characters inside the
218d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // buffer to Spannable once, while CharArrayBuffer is for directly applying char array to
219d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // TextView without any modification.
220d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private final CharArrayBuffer mDataBuffer = new CharArrayBuffer(128);
221d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private final CharArrayBuffer mPhoneticNameBuffer = new CharArrayBuffer(128);
222d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
223d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mActivatedStateSupported;
224fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee    private boolean mAdjustSelectionBoundsEnabled = true;
225d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
226d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private Rect mBoundsWithoutHeader = new Rect();
227d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
228d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /** A helper used to highlight a prefix in a text field. */
229a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    private final TextHighlighter mTextHighlighter;
230d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private CharSequence mUnknownNameText;
231d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
232d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public ContactListItemView(Context context) {
233d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        super(context);
234d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
23542210256d3d584783ac2fb2742088ce57d9da766Yorke Lee        mTextHighlighter = new TextHighlighter(Typeface.BOLD);
236bb67024ef64a7853f5ec320652d80f0cdf7b660fYorke Lee        mNameHighlightSequence = new ArrayList<HighlightSequence>();
237bb67024ef64a7853f5ec320652d80f0cdf7b660fYorke Lee        mNumberHighlightSequence = new ArrayList<HighlightSequence>();
238d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
239d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
240d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public ContactListItemView(Context context, AttributeSet attrs) {
241d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        super(context, attrs);
242d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
24325527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee        TypedArray a;
24425527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee
24525527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee        if (R.styleable.ContactListItemView != null) {
24625527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            // Read all style values
24725527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            a = getContext().obtainStyledAttributes(attrs, R.styleable.ContactListItemView);
24825527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mPreferredHeight = a.getDimensionPixelSize(
24925527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_height, mPreferredHeight);
25025527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mActivatedBackgroundDrawable = a.getDrawable(
25125527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_activated_background);
25225527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee
25325527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mGapBetweenImageAndText = a.getDimensionPixelOffset(
25425527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_gap_between_image_and_text,
25525527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    mGapBetweenImageAndText);
25625527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mGapBetweenLabelAndData = a.getDimensionPixelOffset(
25725527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_gap_between_label_and_data,
25825527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    mGapBetweenLabelAndData);
25925527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mPresenceIconMargin = a.getDimensionPixelOffset(
26025527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_presence_icon_margin,
26125527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    mPresenceIconMargin);
26225527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mPresenceIconSize = a.getDimensionPixelOffset(
26325527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_presence_icon_size,
26425527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    mPresenceIconSize);
26525527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mDefaultPhotoViewSize = a.getDimensionPixelOffset(
26625527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_photo_size, mDefaultPhotoViewSize);
26725527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mTextIndent = a.getDimensionPixelOffset(
26825527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_text_indent, mTextIndent);
26925527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mTextOffsetTop = a.getDimensionPixelOffset(
27025527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_text_offset_top, mTextOffsetTop);
27125527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mDataViewWidthWeight = a.getInteger(
27225527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_data_width_weight,
27325527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    mDataViewWidthWeight);
27425527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mLabelViewWidthWeight = a.getInteger(
27525527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_label_width_weight,
27625527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    mLabelViewWidthWeight);
27725527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mNameTextViewTextColor = a.getColor(
27825527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_name_text_color,
27925527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    mNameTextViewTextColor);
28025527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mNameTextViewTextSize = (int) a.getDimension(
28125527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_name_text_size,
28225527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    (int) getResources().getDimension(R.dimen.contact_browser_list_item_text_size));
28325527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee
28425527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            setPaddingRelative(
28525527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    a.getDimensionPixelOffset(
28625527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                            R.styleable.ContactListItemView_list_item_padding_left, 0),
28725527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    a.getDimensionPixelOffset(
28825527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                            R.styleable.ContactListItemView_list_item_padding_top, 0),
28925527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    a.getDimensionPixelOffset(
29025527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                            R.styleable.ContactListItemView_list_item_padding_right, 0),
29125527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    a.getDimensionPixelOffset(
29225527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                            R.styleable.ContactListItemView_list_item_padding_bottom, 0));
29325527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee
29425527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            a.recycle();
29525527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee        }
296d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
29742210256d3d584783ac2fb2742088ce57d9da766Yorke Lee        mTextHighlighter = new TextHighlighter(Typeface.BOLD);
29842210256d3d584783ac2fb2742088ce57d9da766Yorke Lee
29925527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee        if (R.styleable.Theme != null) {
30025527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            a = getContext().obtainStyledAttributes(R.styleable.Theme);
30125527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mSecondaryTextColor = a.getColorStateList(R.styleable.Theme_android_textColorSecondary);
30225527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            a.recycle();
30325527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee        }
304d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
3051f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee        mHeaderWidth =
3061f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee                getResources().getDimensionPixelSize(R.dimen.contact_list_section_header_width);
3071f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee
308d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mActivatedBackgroundDrawable != null) {
309d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mActivatedBackgroundDrawable.setCallback(this);
310d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
311f99a990be713ed35afe64ba8133c5428816390c6Christine Chen
312f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        mNameHighlightSequence = new ArrayList<HighlightSequence>();
313f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        mNumberHighlightSequence = new ArrayList<HighlightSequence>();
31453c7dc1e9691b5b427395642a4274d37a1a15bb4Yorke Lee
31553c7dc1e9691b5b427395642a4274d37a1a15bb4Yorke Lee        setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE);
316d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
317d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
318d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setUnknownNameText(CharSequence unknownNameText) {
319d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mUnknownNameText = unknownNameText;
320d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
321d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
322d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setQuickContactEnabled(boolean flag) {
323d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mQuickContactEnabled = flag;
324d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
325d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
326d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
327d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
328d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // We will match parent's width and wrap content vertically, but make sure
329d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // height is no less than listPreferredItemHeight.
330d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int specWidth = resolveSize(0, widthMeasureSpec);
331f4fcd3def28e5b1168f5160e476c05ad69339adcAndrew Lee        final int preferredHeight = mPreferredHeight;
332d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
333d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mNameTextViewHeight = 0;
334d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mPhoneticNameTextViewHeight = 0;
335d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mLabelViewHeight = 0;
336d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mDataViewHeight = 0;
337d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mLabelAndDataViewMaxHeight = 0;
338d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mSnippetTextViewHeight = 0;
339d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mStatusTextViewHeight = 0;
34008901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        mCheckBoxWidth = 0;
34108901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        mCheckBoxHeight = 0;
342d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
343d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        ensurePhotoViewSize();
344d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
345d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Width each TextView is able to use.
346ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee        int effectiveWidth;
347d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // All the other Views will honor the photo, so available width for them may be shrunk.
348d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mPhotoViewWidth > 0 || mKeepHorizontalPaddingForPhotoView) {
349d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            effectiveWidth = specWidth - getPaddingLeft() - getPaddingRight()
350d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    - (mPhotoViewWidth + mGapBetweenImageAndText);
351d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
352d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            effectiveWidth = specWidth - getPaddingLeft() - getPaddingRight();
353d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
354d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
355ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee        if (mIsSectionHeaderEnabled) {
356ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee            effectiveWidth -= mHeaderWidth + mGapBetweenImageAndText;
357ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee        }
358ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee
359d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Go over all visible text views and measure actual width of each of them.
360d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Also calculate their heights to get the total height for this entire view.
361d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
36208901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        if (isVisible(mCheckBox)) {
36308901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            mCheckBox.measure(
36408901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
36508901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
36608901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            mCheckBoxWidth = mCheckBox.getMeasuredWidth();
36708901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            mCheckBoxHeight = mCheckBox.getMeasuredHeight();
36808901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            effectiveWidth -= mCheckBoxWidth + mGapBetweenImageAndText;
36908901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        }
37008901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell
371d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mNameTextView)) {
37290fbbae42d4628b18e78434e7de13254099b229ePaul Soulos            // Calculate width for name text - this parallels similar measurement in onLayout.
373d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            int nameTextWidth = effectiveWidth;
374d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mPhotoPosition != PhotoPosition.LEFT) {
375d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                nameTextWidth -= mTextIndent;
376d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
377d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView.measure(
378d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(nameTextWidth, MeasureSpec.EXACTLY),
379d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
380d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextViewHeight = mNameTextView.getMeasuredHeight();
381d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
382d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
383d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mPhoneticNameTextView)) {
384d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.measure(
385d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(effectiveWidth, MeasureSpec.EXACTLY),
386d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
387d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextViewHeight = mPhoneticNameTextView.getMeasuredHeight();
388d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
389d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
390d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // If both data (phone number/email address) and label (type like "MOBILE") are quite long,
391d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // we should ellipsize both using appropriate ratio.
392d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int dataWidth;
393d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int labelWidth;
394d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mDataView)) {
395d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (isVisible(mLabelView)) {
396d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                final int totalWidth = effectiveWidth - mGapBetweenLabelAndData;
397d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                dataWidth = ((totalWidth * mDataViewWidthWeight)
398d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        / (mDataViewWidthWeight + mLabelViewWidthWeight));
399d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                labelWidth = ((totalWidth * mLabelViewWidthWeight) /
400d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        (mDataViewWidthWeight + mLabelViewWidthWeight));
401d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            } else {
402d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                dataWidth = effectiveWidth;
403d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                labelWidth = 0;
404d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
405d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
406d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            dataWidth = 0;
407d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (isVisible(mLabelView)) {
408d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                labelWidth = effectiveWidth;
409d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            } else {
410d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                labelWidth = 0;
411d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
412d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
413d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
414d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mDataView)) {
415d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataView.measure(MeasureSpec.makeMeasureSpec(dataWidth, MeasureSpec.EXACTLY),
416d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
417d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataViewHeight = mDataView.getMeasuredHeight();
418d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
419d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
420d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mLabelView)) {
421d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // For performance reason we don't want AT_MOST usually, but when the picture is
422d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // on right, we need to use it anyway because mDataView is next to mLabelView.
423d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            final int mode = (mPhotoPosition == PhotoPosition.LEFT
424d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    ? MeasureSpec.EXACTLY : MeasureSpec.AT_MOST);
425d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mLabelView.measure(MeasureSpec.makeMeasureSpec(labelWidth, mode),
426d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
427d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mLabelViewHeight = mLabelView.getMeasuredHeight();
428d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
429d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mLabelAndDataViewMaxHeight = Math.max(mLabelViewHeight, mDataViewHeight);
430d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
431d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mSnippetView)) {
432d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.measure(
433d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(effectiveWidth, MeasureSpec.EXACTLY),
434d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
435d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetTextViewHeight = mSnippetView.getMeasuredHeight();
436d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
437d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
438d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Status view height is the biggest of the text view and the presence icon
439d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mPresenceIcon)) {
440d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPresenceIcon.measure(
441d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(mPresenceIconSize, MeasureSpec.EXACTLY),
442d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(mPresenceIconSize, MeasureSpec.EXACTLY));
443d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusTextViewHeight = mPresenceIcon.getMeasuredHeight();
444d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
445d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
446d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mStatusView)) {
447d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Presence and status are in a same row, so status will be affected by icon size.
448d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            final int statusWidth;
449d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (isVisible(mPresenceIcon)) {
450d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                statusWidth = (effectiveWidth - mPresenceIcon.getMeasuredWidth()
451d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        - mPresenceIconMargin);
452d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            } else {
453d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                statusWidth = effectiveWidth;
454d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
455d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView.measure(MeasureSpec.makeMeasureSpec(statusWidth, MeasureSpec.EXACTLY),
456d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
457d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusTextViewHeight =
458d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    Math.max(mStatusTextViewHeight, mStatusView.getMeasuredHeight());
459d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
460d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
461d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Calculate height including padding.
462d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int height = (mNameTextViewHeight + mPhoneticNameTextViewHeight +
463d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelAndDataViewMaxHeight +
464d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mSnippetTextViewHeight + mStatusTextViewHeight);
465d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
466d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Make sure the height is at least as high as the photo
467d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        height = Math.max(height, mPhotoViewHeight + getPaddingBottom() + getPaddingTop());
468d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
469d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Make sure height is at least the preferred height
470d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        height = Math.max(height, preferredHeight);
471d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
4721f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee        // Measure the header if it is visible.
4731f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee        if (mHeaderTextView != null && mHeaderTextView.getVisibility() == VISIBLE) {
474d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mHeaderTextView.measure(
4751f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee                    MeasureSpec.makeMeasureSpec(mHeaderWidth, MeasureSpec.EXACTLY),
4766fdf16941587a222f554482fb72531783a924b6eAndrew Lee                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
477d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
478d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
479d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        setMeasuredDimension(specWidth, height);
480d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
481d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
482d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
483d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
484d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int height = bottom - top;
485d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int width = right - left;
486d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
487d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Determine the vertical bounds by laying out the header first.
488d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int topBound = 0;
489d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int bottomBound = height;
490d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int leftBound = getPaddingLeft();
491d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int rightBound = width - getPaddingRight();
492d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
493864c67691b5a0169b5cbb91469d67d93e24ad9ebYorke Lee        final boolean isLayoutRtl = ViewUtil.isViewLayoutRtl(this);
49409f15e70e86d92ae0f4c15a726b777f170845a3cYorke Lee
4951f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee        // Put the section header on the left side of the contact view.
4961f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee        if (mIsSectionHeaderEnabled) {
4971f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee            if (mHeaderTextView != null) {
4986fdf16941587a222f554482fb72531783a924b6eAndrew Lee                int headerHeight = mHeaderTextView.getMeasuredHeight();
4996fdf16941587a222f554482fb72531783a924b6eAndrew Lee                int headerTopBound = (bottomBound + topBound - headerHeight) / 2 + mTextOffsetTop;
5006fdf16941587a222f554482fb72531783a924b6eAndrew Lee
5011f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee                mHeaderTextView.layout(
5021f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee                        isLayoutRtl ? rightBound - mHeaderWidth : leftBound,
5036fdf16941587a222f554482fb72531783a924b6eAndrew Lee                        headerTopBound,
5041f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee                        isLayoutRtl ? rightBound : leftBound + mHeaderWidth,
5056fdf16941587a222f554482fb72531783a924b6eAndrew Lee                        headerTopBound + headerHeight);
5061f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee            }
5071f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee            if (isLayoutRtl) {
5081f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee                rightBound -= mHeaderWidth;
5091f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee            } else {
5101f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee                leftBound += mHeaderWidth;
5111f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee            }
512d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
513d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
514f7a205fdcb17161c454bee673cc2fce5b23d0760Sai Cheemalapati        mBoundsWithoutHeader.set(left + leftBound, topBound, left + rightBound, bottomBound);
515f7a205fdcb17161c454bee673cc2fce5b23d0760Sai Cheemalapati        mLeftOffset = left + leftBound;
516f7a205fdcb17161c454bee673cc2fce5b23d0760Sai Cheemalapati        mRightOffset = left + rightBound;
517ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee        if (mIsSectionHeaderEnabled) {
518ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee            if (isLayoutRtl) {
519ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee                rightBound -= mGapBetweenImageAndText;
520ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee            } else {
521ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee                leftBound += mGapBetweenImageAndText;
522ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee            }
523ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee        }
524d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
525d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mActivatedStateSupported && isActivated()) {
526d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mActivatedBackgroundDrawable.setBounds(mBoundsWithoutHeader);
527d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
528d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
52908901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        if (isVisible(mCheckBox)) {
53008901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            final int photoTop = topBound + (bottomBound - topBound - mCheckBoxHeight) / 2;
53108901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            if (mPhotoPosition == PhotoPosition.LEFT) {
53208901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                mCheckBox.layout(rightBound - mCheckBoxWidth,
53308901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        photoTop,
53408901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        rightBound,
53508901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        photoTop + mCheckBoxHeight);
53608901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            } else {
53708901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                mCheckBox.layout(leftBound,
53808901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        photoTop,
53908901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        leftBound + mCheckBoxWidth,
54008901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        photoTop + mCheckBoxHeight);
54108901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            }
54208901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        }
54308901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell
544d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final View photoView = mQuickContact != null ? mQuickContact : mPhotoView;
545d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mPhotoPosition == PhotoPosition.LEFT) {
546d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Photo is the left most view. All the other Views should on the right of the photo.
547d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (photoView != null) {
548d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                // Center the photo vertically
549d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                final int photoTop = topBound + (bottomBound - topBound - mPhotoViewHeight) / 2;
550d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                photoView.layout(
551d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        leftBound,
552d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        photoTop,
553d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        leftBound + mPhotoViewWidth,
554d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        photoTop + mPhotoViewHeight);
555d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                leftBound += mPhotoViewWidth + mGapBetweenImageAndText;
556d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            } else if (mKeepHorizontalPaddingForPhotoView) {
557d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                // Draw nothing but keep the padding.
558d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                leftBound += mPhotoViewWidth + mGapBetweenImageAndText;
559d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
560d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
561d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Photo is the right most view. Right bound should be adjusted that way.
562d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (photoView != null) {
563d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                // Center the photo vertically
564d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                final int photoTop = topBound + (bottomBound - topBound - mPhotoViewHeight) / 2;
565d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                photoView.layout(
566d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        rightBound - mPhotoViewWidth,
567d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        photoTop,
568d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        rightBound,
569d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        photoTop + mPhotoViewHeight);
570d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                rightBound -= (mPhotoViewWidth + mGapBetweenImageAndText);
5719f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            } else if (mKeepHorizontalPaddingForPhotoView) {
5729f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                // Draw nothing but keep the padding.
5739f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                rightBound -= (mPhotoViewWidth + mGapBetweenImageAndText);
574d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
575d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
576d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Add indent between left-most padding and texts.
577d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            leftBound += mTextIndent;
578d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
579d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
5807961175eb7b8b8d6f990bd8e510f59fe48c5ef4bAndrew Lee        // Center text vertically, then apply the top offset.
581d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int totalTextHeight = mNameTextViewHeight + mPhoneticNameTextViewHeight +
582d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelAndDataViewMaxHeight + mSnippetTextViewHeight + mStatusTextViewHeight;
5837961175eb7b8b8d6f990bd8e510f59fe48c5ef4bAndrew Lee        int textTopBound = (bottomBound + topBound - totalTextHeight) / 2 + mTextOffsetTop;
584d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
585d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Layout all text view and presence icon
586d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Put name TextView first
587d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mNameTextView)) {
58808901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            final int distanceFromEnd = mCheckBoxWidth > 0
58908901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                    ? mCheckBoxWidth + mGapBetweenImageAndText : 0;
59008901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            if (mPhotoPosition == PhotoPosition.LEFT) {
59108901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                mNameTextView.layout(leftBound,
59208901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        textTopBound,
59308901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        rightBound - distanceFromEnd,
59408901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        textTopBound + mNameTextViewHeight);
59508901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            } else {
59608901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                mNameTextView.layout(leftBound + distanceFromEnd,
59708901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        textTopBound,
59808901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        rightBound,
59908901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        textTopBound + mNameTextViewHeight);
60008901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            }
601d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textTopBound += mNameTextViewHeight;
602d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
603d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
604d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Presence and status
6059f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        if (isLayoutRtl) {
6069f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            int statusRightBound = rightBound;
6079f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            if (isVisible(mPresenceIcon)) {
6089f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                int iconWidth = mPresenceIcon.getMeasuredWidth();
6099f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                mPresenceIcon.layout(
6109f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        rightBound - iconWidth,
6119f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound,
6129f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        rightBound,
6139f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound + mStatusTextViewHeight);
6149f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                statusRightBound -= (iconWidth + mPresenceIconMargin);
6159f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            }
616d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
6179f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            if (isVisible(mStatusView)) {
6189f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                mStatusView.layout(leftBound,
6199f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound,
6209f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        statusRightBound,
6219f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound + mStatusTextViewHeight);
6229f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            }
6239f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        } else {
6249f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            int statusLeftBound = leftBound;
6259f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            if (isVisible(mPresenceIcon)) {
6269f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                int iconWidth = mPresenceIcon.getMeasuredWidth();
6279f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                mPresenceIcon.layout(
6289f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        leftBound,
6299f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound,
6309f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        leftBound + iconWidth,
6319f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound + mStatusTextViewHeight);
6329f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                statusLeftBound += (iconWidth + mPresenceIconMargin);
6339f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            }
6349f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio
6359f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            if (isVisible(mStatusView)) {
6369f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                mStatusView.layout(statusLeftBound,
6379f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound,
6389f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        rightBound,
6399f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound + mStatusTextViewHeight);
6409f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            }
641d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
642d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
643d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mStatusView) || isVisible(mPresenceIcon)) {
644d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textTopBound += mStatusTextViewHeight;
645d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
646d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
647d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Rest of text views
648d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int dataLeftBound = leftBound;
649d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mPhoneticNameTextView)) {
650d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.layout(leftBound,
651d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    textTopBound,
652d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    rightBound,
653d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    textTopBound + mPhoneticNameTextViewHeight);
654d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textTopBound += mPhoneticNameTextViewHeight;
655d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
656d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
657d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Label and Data align bottom.
658d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mLabelView)) {
659d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mPhotoPosition == PhotoPosition.LEFT) {
660d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                // When photo is on left, label is placed on the right edge of the list item.
661d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelView.layout(rightBound - mLabelView.getMeasuredWidth(),
662d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        textTopBound + mLabelAndDataViewMaxHeight - mLabelViewHeight,
663d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        rightBound,
664d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        textTopBound + mLabelAndDataViewMaxHeight);
665d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                rightBound -= mLabelView.getMeasuredWidth();
666d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            } else {
667d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                // When photo is on right, label is placed on the left of data view.
668d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                dataLeftBound = leftBound + mLabelView.getMeasuredWidth();
669d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelView.layout(leftBound,
670d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        textTopBound + mLabelAndDataViewMaxHeight - mLabelViewHeight,
671d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        dataLeftBound,
672d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        textTopBound + mLabelAndDataViewMaxHeight);
673d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                dataLeftBound += mGapBetweenLabelAndData;
674d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
675d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
676d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
677d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mDataView)) {
678d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataView.layout(dataLeftBound,
679d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    textTopBound + mLabelAndDataViewMaxHeight - mDataViewHeight,
680d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    rightBound,
681d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    textTopBound + mLabelAndDataViewMaxHeight);
682d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
683d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mLabelView) || isVisible(mDataView)) {
684d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textTopBound += mLabelAndDataViewMaxHeight;
685d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
686d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
687d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mSnippetView)) {
688d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.layout(leftBound,
689d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    textTopBound,
690d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    rightBound,
691d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    textTopBound + mSnippetTextViewHeight);
692d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
693d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
694d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
695d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
696d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void adjustListItemSelectionBounds(Rect bounds) {
697fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee        if (mAdjustSelectionBoundsEnabled) {
698fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee            bounds.top += mBoundsWithoutHeader.top;
699fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee            bounds.bottom = bounds.top + mBoundsWithoutHeader.height();
700fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee            bounds.left = mBoundsWithoutHeader.left;
701fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee            bounds.right = mBoundsWithoutHeader.right;
702fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee        }
703d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
704d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
705d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected boolean isVisible(View view) {
706d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return view != null && view.getVisibility() == View.VISIBLE;
707d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
708d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
709d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
710d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Extracts width and height from the style
711d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
712d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private void ensurePhotoViewSize() {
713d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (!mPhotoViewWidthAndHeightAreReady) {
714d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoViewWidth = mPhotoViewHeight = getDefaultPhotoViewSize();
715d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (!mQuickContactEnabled && mPhotoView == null) {
716d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                if (!mKeepHorizontalPaddingForPhotoView) {
717d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    mPhotoViewWidth = 0;
718d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                }
719d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                if (!mKeepVerticalPaddingForPhotoView) {
720d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    mPhotoViewHeight = 0;
721d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                }
722d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
723d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
724d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoViewWidthAndHeightAreReady = true;
725d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
726d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
727d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
728d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected int getDefaultPhotoViewSize() {
729d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mDefaultPhotoViewSize;
730d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
731d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
732d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
733d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Gets a LayoutParam that corresponds to the default photo size.
734d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     *
735d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * @return A new LayoutParam.
736d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
737d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private LayoutParams getDefaultPhotoLayoutParams() {
738d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        LayoutParams params = generateDefaultLayoutParams();
739d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        params.width = getDefaultPhotoViewSize();
740d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        params.height = params.width;
741d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return params;
742d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
743d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
744d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
745d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected void drawableStateChanged() {
746d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        super.drawableStateChanged();
747d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mActivatedStateSupported) {
748d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mActivatedBackgroundDrawable.setState(getDrawableState());
749d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
750d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
751d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
752d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
753d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected boolean verifyDrawable(Drawable who) {
754d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return who == mActivatedBackgroundDrawable || super.verifyDrawable(who);
755d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
756d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
757d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
758d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void jumpDrawablesToCurrentState() {
759d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        super.jumpDrawablesToCurrentState();
760d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mActivatedStateSupported) {
761d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mActivatedBackgroundDrawable.jumpToCurrentState();
762d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
763d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
764d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
765d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
766d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void dispatchDraw(Canvas canvas) {
767d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mActivatedStateSupported && isActivated()) {
768d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mActivatedBackgroundDrawable.draw(canvas);
769d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
770d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
771d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        super.dispatchDraw(canvas);
772d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
773d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
774d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
775d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Sets section header or makes it invisible if the title is null.
776d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
777d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setSectionHeader(String title) {
778d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (!TextUtils.isEmpty(title)) {
779d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mHeaderTextView == null) {
780e9736747aa45ed6091a5479b38e3311823675853Yorke Lee                mHeaderTextView = new TextView(getContext());
781e9736747aa45ed6091a5479b38e3311823675853Yorke Lee                mHeaderTextView.setTextAppearance(getContext(), R.style.SectionHeaderStyle);
7826fdf16941587a222f554482fb72531783a924b6eAndrew Lee                mHeaderTextView.setGravity(
7836fdf16941587a222f554482fb72531783a924b6eAndrew Lee                        ViewUtil.isViewLayoutRtl(this) ? Gravity.RIGHT : Gravity.LEFT);
784d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                addView(mHeaderTextView);
785d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
786d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setMarqueeText(mHeaderTextView, title);
787d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mHeaderTextView.setVisibility(View.VISIBLE);
788d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mHeaderTextView.setAllCaps(true);
7891f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee        } else if (mHeaderTextView != null) {
7901f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee            mHeaderTextView.setVisibility(View.GONE);
791d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
792d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
793d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
7941f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee    public void setIsSectionHeaderEnabled(boolean isSectionHeaderEnabled) {
7951f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee        mIsSectionHeaderEnabled = isSectionHeaderEnabled;
7961f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee    }
7971f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee
798d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
799d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the quick contact badge, creating it if necessary.
800d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
801d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public QuickContactBadge getQuickContact() {
802d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (!mQuickContactEnabled) {
803d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            throw new IllegalStateException("QuickContact is disabled for this view");
804d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
805d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mQuickContact == null) {
806e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mQuickContact = new QuickContactBadge(getContext());
8073f9c2f426058413055fa54c08c69ad9461717658Yorke Lee            mQuickContact.setOverlay(null);
808d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mQuickContact.setLayoutParams(getDefaultPhotoLayoutParams());
809d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mNameTextView != null) {
810e9736747aa45ed6091a5479b38e3311823675853Yorke Lee                mQuickContact.setContentDescription(getContext().getString(
811d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        R.string.description_quick_contact_for, mNameTextView.getText()));
812d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
813d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
814d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mQuickContact);
815d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoViewWidthAndHeightAreReady = false;
816d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
817d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mQuickContact;
818d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
819d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
820d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
821d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the photo view, creating it if necessary.
822d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
823d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public ImageView getPhotoView() {
824d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mPhotoView == null) {
825e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mPhotoView = new ImageView(getContext());
826d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoView.setLayoutParams(getDefaultPhotoLayoutParams());
827d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Quick contact style used above will set a background - remove it
828d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoView.setBackground(null);
829d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mPhotoView);
830d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoViewWidthAndHeightAreReady = false;
831d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
832d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mPhotoView;
833d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
834d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
835d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
836d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Removes the photo view.
837d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
838d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void removePhotoView() {
839d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        removePhotoView(false, true);
840d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
841d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
842d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
843d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Removes the photo view.
844d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     *
845d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * @param keepHorizontalPadding True means data on the right side will have
846d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     *            padding on left, pretending there is still a photo view.
847d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * @param keepVerticalPadding True means the View will have some height
848d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     *            enough for accommodating a photo view.
849d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
850d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void removePhotoView(boolean keepHorizontalPadding, boolean keepVerticalPadding) {
851d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mPhotoViewWidthAndHeightAreReady = false;
852d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mKeepHorizontalPaddingForPhotoView = keepHorizontalPadding;
853d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mKeepVerticalPaddingForPhotoView = keepVerticalPadding;
854d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mPhotoView != null) {
855d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            removeView(mPhotoView);
856d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoView = null;
857d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
858d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mQuickContact != null) {
859d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            removeView(mQuickContact);
860d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mQuickContact = null;
861d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
862d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
863d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
864d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
865d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Sets a word prefix that will be highlighted if encountered in fields like
866a81953a2b1818066ef5e44817f374ac288bab343Christine Chen     * name and search snippet. This will disable the mask highlighting for names.
867d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * <p>
868d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * NOTE: must be all upper-case
869d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
870bd80fd64b9ff94c9ffbdb843beb4b363bb209463Chiao Cheng    public void setHighlightedPrefix(String upperCasePrefix) {
871d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mHighlightedPrefix = upperCasePrefix;
872a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    }
873a81953a2b1818066ef5e44817f374ac288bab343Christine Chen
874a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    /**
875f99a990be713ed35afe64ba8133c5428816390c6Christine Chen     * Clears previously set highlight sequences for the view.
876a81953a2b1818066ef5e44817f374ac288bab343Christine Chen     */
877f99a990be713ed35afe64ba8133c5428816390c6Christine Chen    public void clearHighlightSequences() {
878f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        mNameHighlightSequence.clear();
879f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        mNumberHighlightSequence.clear();
880a81953a2b1818066ef5e44817f374ac288bab343Christine Chen        mHighlightedPrefix = null;
881a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    }
882a81953a2b1818066ef5e44817f374ac288bab343Christine Chen
883a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    /**
884f99a990be713ed35afe64ba8133c5428816390c6Christine Chen     * Adds a highlight sequence to the name highlighter.
885f99a990be713ed35afe64ba8133c5428816390c6Christine Chen     * @param start The start position of the highlight sequence.
886f99a990be713ed35afe64ba8133c5428816390c6Christine Chen     * @param end The end position of the highlight sequence.
887f99a990be713ed35afe64ba8133c5428816390c6Christine Chen     */
888f99a990be713ed35afe64ba8133c5428816390c6Christine Chen    public void addNameHighlightSequence(int start, int end) {
889f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        mNameHighlightSequence.add(new HighlightSequence(start, end));
890f99a990be713ed35afe64ba8133c5428816390c6Christine Chen    }
891f99a990be713ed35afe64ba8133c5428816390c6Christine Chen
892f99a990be713ed35afe64ba8133c5428816390c6Christine Chen    /**
893f99a990be713ed35afe64ba8133c5428816390c6Christine Chen     * Adds a highlight sequence to the number highlighter.
894f99a990be713ed35afe64ba8133c5428816390c6Christine Chen     * @param start The start position of the highlight sequence.
895f99a990be713ed35afe64ba8133c5428816390c6Christine Chen     * @param end The end position of the highlight sequence.
896a81953a2b1818066ef5e44817f374ac288bab343Christine Chen     */
897f99a990be713ed35afe64ba8133c5428816390c6Christine Chen    public void addNumberHighlightSequence(int start, int end) {
898f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        mNumberHighlightSequence.add(new HighlightSequence(start, end));
899d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
900d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
901d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
902d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the text view for the contact name, creating it if necessary.
903d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
904d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public TextView getNameTextView() {
905d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mNameTextView == null) {
906e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mNameTextView = new TextView(getContext());
907d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView.setSingleLine(true);
908d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView.setEllipsize(getTextEllipsis());
909f88b7b9d1a07414053a4a90d13d453a02bd58ac7Nancy Chen            mNameTextView.setTextColor(mNameTextViewTextColor);
9103bc19a3bb1ed23b03352fff6de69a89e763a315eSai Cheemalapati            mNameTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
9113bc19a3bb1ed23b03352fff6de69a89e763a315eSai Cheemalapati                    mNameTextViewTextSize);
912d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Manually call setActivated() since this view may be added after the first
913d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // setActivated() call toward this whole item view.
914d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView.setActivated(isActivated());
915d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView.setGravity(Gravity.CENTER_VERTICAL);
9169f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            mNameTextView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
9179f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            mNameTextView.setId(R.id.cliv_name_textview);
9187961175eb7b8b8d6f990bd8e510f59fe48c5ef4bAndrew Lee            mNameTextView.setElegantTextHeight(false);
919d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mNameTextView);
920d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
921d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mNameTextView;
922d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
923d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
924d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
925d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Adds or updates a text view for the phonetic name.
926d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
927d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setPhoneticName(char[] text, int size) {
928d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (text == null || size == 0) {
929d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mPhoneticNameTextView != null) {
930d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mPhoneticNameTextView.setVisibility(View.GONE);
931d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
932d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
933d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            getPhoneticNameTextView();
934d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setMarqueeText(mPhoneticNameTextView, text, size);
935d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.setVisibility(VISIBLE);
936d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
937d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
938d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
939d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
940d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the text view for the phonetic name, creating it if necessary.
941d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
942d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public TextView getPhoneticNameTextView() {
943d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mPhoneticNameTextView == null) {
944e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mPhoneticNameTextView = new TextView(getContext());
945d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.setSingleLine(true);
946d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.setEllipsize(getTextEllipsis());
947e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mPhoneticNameTextView.setTextAppearance(getContext(), android.R.style.TextAppearance_Small);
9486f2673a25ecc59426c2faa2cfec5780e59ac5e5eWalter Jang            mPhoneticNameTextView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
949d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.setTypeface(mPhoneticNameTextView.getTypeface(), Typeface.BOLD);
950d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.setActivated(isActivated());
9519f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            mPhoneticNameTextView.setId(R.id.cliv_phoneticname_textview);
952d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mPhoneticNameTextView);
953d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
954d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mPhoneticNameTextView;
955d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
956d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
957d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
958d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Adds or updates a text view for the data label.
959d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
960d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setLabel(CharSequence text) {
961d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (TextUtils.isEmpty(text)) {
962d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mLabelView != null) {
963d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelView.setVisibility(View.GONE);
964d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
965d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
966d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            getLabelView();
967d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setMarqueeText(mLabelView, text);
968d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mLabelView.setVisibility(VISIBLE);
969d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
970d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
971d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
972d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
973d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the text view for the data label, creating it if necessary.
974d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
975d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public TextView getLabelView() {
976d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mLabelView == null) {
977e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mLabelView = new TextView(getContext());
978d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mLabelView.setSingleLine(true);
979d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mLabelView.setEllipsize(getTextEllipsis());
98090a368279bb3e94291e12fc0c7dc8676f194c33dYorke Lee            mLabelView.setTextAppearance(getContext(), R.style.TextAppearanceSmall);
981d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mPhotoPosition == PhotoPosition.LEFT) {
982d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelView.setAllCaps(true);
9839f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                mLabelView.setGravity(Gravity.END);
984d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            } else {
985d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelView.setTypeface(mLabelView.getTypeface(), Typeface.BOLD);
986d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
987d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mLabelView.setActivated(isActivated());
9889f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            mLabelView.setId(R.id.cliv_label_textview);
989d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mLabelView);
990d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
991d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mLabelView;
992d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
993d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
994d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
995d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Adds or updates a text view for the data element.
996d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
997a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    public void setData(char[] text, int size) {
998d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (text == null || size == 0) {
999d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mDataView != null) {
1000d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mDataView.setVisibility(View.GONE);
1001d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1002d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1003d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            getDataView();
1004d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setMarqueeText(mDataView, text, size);
1005d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataView.setVisibility(VISIBLE);
1006a81953a2b1818066ef5e44817f374ac288bab343Christine Chen        }
1007a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    }
1008a81953a2b1818066ef5e44817f374ac288bab343Christine Chen
1009a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    /**
1010a81953a2b1818066ef5e44817f374ac288bab343Christine Chen     * Sets phone number for a list item. This takes care of number highlighting if the highlight
1011a81953a2b1818066ef5e44817f374ac288bab343Christine Chen     * mask exists.
1012a81953a2b1818066ef5e44817f374ac288bab343Christine Chen     */
101362dbbf2f10e0e3bcb4d699d859a71a68c896f4a7Andrew Lee    public void setPhoneNumber(String text, String countryIso) {
1014a81953a2b1818066ef5e44817f374ac288bab343Christine Chen        if (text == null) {
1015a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            if (mDataView != null) {
1016a81953a2b1818066ef5e44817f374ac288bab343Christine Chen                mDataView.setVisibility(View.GONE);
10179f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            }
1018a81953a2b1818066ef5e44817f374ac288bab343Christine Chen        } else {
1019a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            getDataView();
102062dbbf2f10e0e3bcb4d699d859a71a68c896f4a7Andrew Lee
1021eabf27292960173c0600e022c64919453741c93fYorke Lee            // TODO: Format number using PhoneNumberUtils.formatNumber before assigning it to
1022eabf27292960173c0600e022c64919453741c93fYorke Lee            // mDataView. Make sure that determination of the highlight sequences are done only
1023eabf27292960173c0600e022c64919453741c93fYorke Lee            // after number formatting.
102462dbbf2f10e0e3bcb4d699d859a71a68c896f4a7Andrew Lee
1025a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            // Sets phone number texts for display after highlighting it, if applicable.
102662dbbf2f10e0e3bcb4d699d859a71a68c896f4a7Andrew Lee            // CharSequence textToSet = text;
1027f99a990be713ed35afe64ba8133c5428816390c6Christine Chen            final SpannableString textToSet = new SpannableString(text);
1028f99a990be713ed35afe64ba8133c5428816390c6Christine Chen
1029f99a990be713ed35afe64ba8133c5428816390c6Christine Chen            if (mNumberHighlightSequence.size() != 0) {
1030f99a990be713ed35afe64ba8133c5428816390c6Christine Chen                final HighlightSequence highlightSequence = mNumberHighlightSequence.get(0);
1031f99a990be713ed35afe64ba8133c5428816390c6Christine Chen                mTextHighlighter.applyMaskingHighlight(textToSet, highlightSequence.start,
1032f99a990be713ed35afe64ba8133c5428816390c6Christine Chen                        highlightSequence.end);
1033a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            }
1034f99a990be713ed35afe64ba8133c5428816390c6Christine Chen
1035a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            setMarqueeText(mDataView, textToSet);
1036a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            mDataView.setVisibility(VISIBLE);
1037a81953a2b1818066ef5e44817f374ac288bab343Christine Chen
1038a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            // We have a phone number as "mDataView" so make it always LTR and VIEW_START
1039a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            mDataView.setTextDirection(View.TEXT_DIRECTION_LTR);
1040a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            mDataView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
1041d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1042d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1043d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1044d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private void setMarqueeText(TextView textView, char[] text, int size) {
1045d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (getTextEllipsis() == TruncateAt.MARQUEE) {
1046d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setMarqueeText(textView, new String(text, 0, size));
1047d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1048d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textView.setText(text, 0, size);
1049d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1050d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1051d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1052d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private void setMarqueeText(TextView textView, CharSequence text) {
1053d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (getTextEllipsis() == TruncateAt.MARQUEE) {
1054d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // To show MARQUEE correctly (with END effect during non-active state), we need
1055d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // to build Spanned with MARQUEE in addition to TextView's ellipsize setting.
1056d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            final SpannableString spannable = new SpannableString(text);
1057d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            spannable.setSpan(TruncateAt.MARQUEE, 0, spannable.length(),
1058d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
1059d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textView.setText(spannable);
1060d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1061d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textView.setText(text);
1062d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1063d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1064d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1065d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
106608901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell     * Returns the {@link CheckBox} view, creating it if necessary.
106708901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell     */
106808901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell    public CheckBox getCheckBox() {
106908901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        if (mCheckBox == null) {
107008901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            mCheckBox = new CheckBox(getContext());
107108901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            // Make non-focusable, so the rest of the ContactListItemView can be clicked.
107208901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            mCheckBox.setFocusable(false);
107308901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            addView(mCheckBox);
107408901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        }
107508901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        return mCheckBox;
107608901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell    }
107708901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell
107808901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell    /**
1079d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the text view for the data text, creating it if necessary.
1080d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1081d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public TextView getDataView() {
1082d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mDataView == null) {
1083e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mDataView = new TextView(getContext());
1084d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataView.setSingleLine(true);
1085d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataView.setEllipsize(getTextEllipsis());
108690a368279bb3e94291e12fc0c7dc8676f194c33dYorke Lee            mDataView.setTextAppearance(getContext(), R.style.TextAppearanceSmall);
10876f2673a25ecc59426c2faa2cfec5780e59ac5e5eWalter Jang            mDataView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
1088d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataView.setActivated(isActivated());
10899f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            mDataView.setId(R.id.cliv_data_view);
10907961175eb7b8b8d6f990bd8e510f59fe48c5ef4bAndrew Lee            mDataView.setElegantTextHeight(false);
1091d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mDataView);
1092d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1093d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mDataView;
1094d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1095d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1096d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1097d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Adds or updates a text view for the search snippet.
1098d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1099d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setSnippet(String text) {
1100d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (TextUtils.isEmpty(text)) {
1101d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mSnippetView != null) {
1102d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mSnippetView.setVisibility(View.GONE);
1103d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1104d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1105f99a990be713ed35afe64ba8133c5428816390c6Christine Chen            mTextHighlighter.setPrefixText(getSnippetView(), text, mHighlightedPrefix);
1106d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.setVisibility(VISIBLE);
1107d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang            if (ContactDisplayUtils.isPossiblePhoneNumber(text)) {
1108d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang                // Give the text-to-speech engine a hint that it's a phone number
1109c30de25fea532591e85c33966e04aa1443710eabBrian Attwell                mSnippetView.setContentDescription(PhoneNumberUtils.createTtsSpannable(text));
1110d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang            } else {
1111d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang                mSnippetView.setContentDescription(null);
1112d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang            }
1113d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1114d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1115d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1116d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1117d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the text view for the search snippet, creating it if necessary.
1118d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1119d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public TextView getSnippetView() {
1120d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mSnippetView == null) {
1121e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mSnippetView = new TextView(getContext());
1122d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.setSingleLine(true);
1123d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.setEllipsize(getTextEllipsis());
1124e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mSnippetView.setTextAppearance(getContext(), android.R.style.TextAppearance_Small);
11256f2673a25ecc59426c2faa2cfec5780e59ac5e5eWalter Jang            mSnippetView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
1126d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.setActivated(isActivated());
1127d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mSnippetView);
1128d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1129d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mSnippetView;
1130d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1131d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1132d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1133d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the text view for the status, creating it if necessary.
1134d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1135d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public TextView getStatusView() {
1136d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mStatusView == null) {
1137e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mStatusView = new TextView(getContext());
1138d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView.setSingleLine(true);
1139d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView.setEllipsize(getTextEllipsis());
1140e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mStatusView.setTextAppearance(getContext(), android.R.style.TextAppearance_Small);
1141d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView.setTextColor(mSecondaryTextColor);
1142d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView.setActivated(isActivated());
11439f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            mStatusView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
1144d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mStatusView);
1145d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1146d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mStatusView;
1147d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1148d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1149d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1150d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Adds or updates a text view for the status.
1151d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1152d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setStatus(CharSequence text) {
1153d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (TextUtils.isEmpty(text)) {
1154d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mStatusView != null) {
1155d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mStatusView.setVisibility(View.GONE);
1156d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1157d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1158d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            getStatusView();
1159d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setMarqueeText(mStatusView, text);
1160d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView.setVisibility(VISIBLE);
1161d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1162d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1163d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1164d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1165d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Adds or updates the presence icon view.
1166d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1167d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setPresence(Drawable icon) {
1168d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (icon != null) {
1169d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mPresenceIcon == null) {
1170e9736747aa45ed6091a5479b38e3311823675853Yorke Lee                mPresenceIcon = new ImageView(getContext());
1171d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                addView(mPresenceIcon);
1172d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1173d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPresenceIcon.setImageDrawable(icon);
1174d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPresenceIcon.setScaleType(ScaleType.CENTER);
1175d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPresenceIcon.setVisibility(View.VISIBLE);
1176d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1177d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mPresenceIcon != null) {
1178d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mPresenceIcon.setVisibility(View.GONE);
1179d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1180d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1181d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1182d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1183d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TruncateAt getTextEllipsis() {
1184d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return TruncateAt.MARQUEE;
1185d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1186d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1187d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void showDisplayName(Cursor cursor, int nameColumnIndex, int displayOrder) {
1188d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        CharSequence name = cursor.getString(nameColumnIndex);
118927330d80bb6575df2964112d34143125c8af9b78Yorke Lee        setDisplayName(name);
119027330d80bb6575df2964112d34143125c8af9b78Yorke Lee
119127330d80bb6575df2964112d34143125c8af9b78Yorke Lee        // Since the quick contact content description is derived from the display name and there is
119227330d80bb6575df2964112d34143125c8af9b78Yorke Lee        // no guarantee that when the quick contact is initialized the display name is already set,
119327330d80bb6575df2964112d34143125c8af9b78Yorke Lee        // do it here too.
119427330d80bb6575df2964112d34143125c8af9b78Yorke Lee        if (mQuickContact != null) {
1195e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mQuickContact.setContentDescription(getContext().getString(
119627330d80bb6575df2964112d34143125c8af9b78Yorke Lee                    R.string.description_quick_contact_for, mNameTextView.getText()));
119727330d80bb6575df2964112d34143125c8af9b78Yorke Lee        }
119827330d80bb6575df2964112d34143125c8af9b78Yorke Lee    }
119927330d80bb6575df2964112d34143125c8af9b78Yorke Lee
120027330d80bb6575df2964112d34143125c8af9b78Yorke Lee    public void setDisplayName(CharSequence name, boolean highlight) {
120127330d80bb6575df2964112d34143125c8af9b78Yorke Lee        if (!TextUtils.isEmpty(name) && highlight) {
120227330d80bb6575df2964112d34143125c8af9b78Yorke Lee            clearHighlightSequences();
120327330d80bb6575df2964112d34143125c8af9b78Yorke Lee            addNameHighlightSequence(0, name.length());
120427330d80bb6575df2964112d34143125c8af9b78Yorke Lee        }
120527330d80bb6575df2964112d34143125c8af9b78Yorke Lee        setDisplayName(name);
120627330d80bb6575df2964112d34143125c8af9b78Yorke Lee    }
120727330d80bb6575df2964112d34143125c8af9b78Yorke Lee
120827330d80bb6575df2964112d34143125c8af9b78Yorke Lee    public void setDisplayName(CharSequence name) {
1209d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (!TextUtils.isEmpty(name)) {
1210a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            // Chooses the available highlighting method for highlighting.
1211a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            if (mHighlightedPrefix != null) {
1212a81953a2b1818066ef5e44817f374ac288bab343Christine Chen                name = mTextHighlighter.applyPrefixHighlight(name, mHighlightedPrefix);
1213f99a990be713ed35afe64ba8133c5428816390c6Christine Chen            } else if (mNameHighlightSequence.size() != 0) {
1214f99a990be713ed35afe64ba8133c5428816390c6Christine Chen                final SpannableString spannableName = new SpannableString(name);
1215f99a990be713ed35afe64ba8133c5428816390c6Christine Chen                for (HighlightSequence highlightSequence : mNameHighlightSequence) {
1216f99a990be713ed35afe64ba8133c5428816390c6Christine Chen                    mTextHighlighter.applyMaskingHighlight(spannableName, highlightSequence.start,
1217f99a990be713ed35afe64ba8133c5428816390c6Christine Chen                            highlightSequence.end);
1218f99a990be713ed35afe64ba8133c5428816390c6Christine Chen                }
1219f99a990be713ed35afe64ba8133c5428816390c6Christine Chen                name = spannableName;
1220a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            }
1221d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1222d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            name = mUnknownNameText;
1223d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1224d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        setMarqueeText(getNameTextView(), name);
1225d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang
1226d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang        if (ContactDisplayUtils.isPossiblePhoneNumber(name)) {
1227d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang            // Give the text-to-speech engine a hint that it's a phone number
12287b03f132552cbee9b5df1958621bcf808217c2c6Tingting Wang            mNameTextView.setTextDirection(View.TEXT_DIRECTION_LTR);
1229d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang            mNameTextView.setContentDescription(
1230c30de25fea532591e85c33966e04aa1443710eabBrian Attwell                    PhoneNumberUtils.createTtsSpannable(name.toString()));
1231d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang        } else {
1232d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang            mNameTextView.setContentDescription(null);
1233d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang        }
1234d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1235d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
123608901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell    public void hideCheckBox() {
123708901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        if (mCheckBox != null) {
123808901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            removeView(mCheckBox);
123908901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            mCheckBox = null;
124008901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        }
124108901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell    }
124208901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell
1243d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void hideDisplayName() {
1244d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mNameTextView != null) {
1245d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            removeView(mNameTextView);
1246d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView = null;
1247d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1248d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1249d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1250d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void showPhoneticName(Cursor cursor, int phoneticNameColumnIndex) {
1251d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        cursor.copyStringToBuffer(phoneticNameColumnIndex, mPhoneticNameBuffer);
1252d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int phoneticNameSize = mPhoneticNameBuffer.sizeCopied;
1253d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (phoneticNameSize != 0) {
1254d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setPhoneticName(mPhoneticNameBuffer.data, phoneticNameSize);
1255d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1256d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setPhoneticName(null, 0);
1257d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1258d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1259d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1260d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void hidePhoneticName() {
1261d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mPhoneticNameTextView != null) {
1262d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            removeView(mPhoneticNameTextView);
1263d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView = null;
1264d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1265d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1266d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1267d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1268d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Sets the proper icon (star or presence or nothing) and/or status message.
1269d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1270d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void showPresenceAndStatusMessage(Cursor cursor, int presenceColumnIndex,
1271d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            int contactStatusColumnIndex) {
1272d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        Drawable icon = null;
1273d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int presence = 0;
1274d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (!cursor.isNull(presenceColumnIndex)) {
1275d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            presence = cursor.getInt(presenceColumnIndex);
1276d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            icon = ContactPresenceIconUtil.getPresenceIcon(getContext(), presence);
1277d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1278d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        setPresence(icon);
1279d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1280d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        String statusMessage = null;
1281d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (contactStatusColumnIndex != 0 && !cursor.isNull(contactStatusColumnIndex)) {
1282d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            statusMessage = cursor.getString(contactStatusColumnIndex);
1283d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1284d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // If there is no status message from the contact, but there was a presence value, then use
1285d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // the default status message string
1286d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (statusMessage == null && presence != 0) {
1287d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            statusMessage = ContactStatusUtil.getStatusString(getContext(), presence);
1288d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1289d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        setStatus(statusMessage);
1290d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1291d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1292d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1293d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Shows search snippet.
1294d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1295d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void showSnippet(Cursor cursor, int summarySnippetColumnIndex) {
1296d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (cursor.getColumnCount() <= summarySnippetColumnIndex) {
1297d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setSnippet(null);
1298d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            return;
1299d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1300d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
130105897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        String snippet = cursor.getString(summarySnippetColumnIndex);
1302cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1303d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Do client side snippeting if provider didn't do it
130405897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        final Bundle extras = cursor.getExtras();
1305d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (extras.getBoolean(ContactsContract.DEFERRED_SNIPPETING)) {
1306d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
130705897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng            final String query = extras.getString(ContactsContract.DEFERRED_SNIPPETING_QUERY);
1308cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1309cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            String displayName = null;
1310cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            int displayNameIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
1311cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            if (displayNameIndex >= 0) {
1312cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                displayName = cursor.getString(displayNameIndex);
131305897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng            }
1314cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1315cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            snippet = updateSnippet(snippet, query, displayName);
1316cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
131705897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        } else {
131805897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng            if (snippet != null) {
131905897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                int from = 0;
132005897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                int to = snippet.length();
132105897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                int start = snippet.indexOf(DefaultContactListAdapter.SNIPPET_START_MATCH);
132205897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                if (start == -1) {
132305897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    snippet = null;
132405897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                } else {
132505897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    int firstNl = snippet.lastIndexOf('\n', start);
132605897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    if (firstNl != -1) {
132705897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        from = firstNl + 1;
132805897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    }
132905897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    int end = snippet.lastIndexOf(DefaultContactListAdapter.SNIPPET_END_MATCH);
133005897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    if (end != -1) {
133105897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        int lastNl = snippet.indexOf('\n', end);
133205897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        if (lastNl != -1) {
133305897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                            to = lastNl;
133405897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        }
133505897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    }
1336d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
133705897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    StringBuilder sb = new StringBuilder();
133805897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    for (int i = from; i < to; i++) {
133905897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        char c = snippet.charAt(i);
134005897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        if (c != DefaultContactListAdapter.SNIPPET_START_MATCH &&
134105897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                                c != DefaultContactListAdapter.SNIPPET_END_MATCH) {
134205897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                            sb.append(c);
134305897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        }
1344d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    }
134505897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    snippet = sb.toString();
1346d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                }
1347d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1348d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1349cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1350d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        setSnippet(snippet);
1351d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1352d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1353cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng    /**
1354cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     * Used for deferred snippets from the database. The contents come back as large strings which
1355cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     * need to be extracted for display.
1356cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     *
1357cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     * @param snippet The snippet from the database.
1358cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     * @param query The search query substring.
1359cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     * @param displayName The contact display name.
1360cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     * @return The proper snippet to display.
1361cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     */
1362cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng    private String updateSnippet(String snippet, String query, String displayName) {
1363cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1364cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        if (TextUtils.isEmpty(snippet) || TextUtils.isEmpty(query)) {
1365cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            return null;
1366cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1367cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        query = SearchUtil.cleanStartAndEndOfSearchQuery(query.toLowerCase());
1368cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1369cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // If the display name already contains the query term, return empty - snippets should
1370cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // not be needed in that case.
1371cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        if (!TextUtils.isEmpty(displayName)) {
1372cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            final String lowerDisplayName = displayName.toLowerCase();
1373cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            final List<String> nameTokens = split(lowerDisplayName);
1374cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            for (String nameToken : nameTokens) {
1375cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                if (nameToken.startsWith(query)) {
1376cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                    return null;
1377cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                }
1378cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            }
1379cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1380cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1381cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // The snippet may contain multiple data lines.
1382cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Show the first line that matches the query.
1383cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        final SearchUtil.MatchedLine matched = SearchUtil.findMatchingLine(snippet, query);
1384cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1385cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        if (matched != null && matched.line != null) {
1386cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            // Tokenize for long strings since the match may be at the end of it.
1387cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            // Skip this part for short strings since the whole string will be displayed.
1388cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            // Most contact strings are short so the snippetize method will be called infrequently.
1389cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            final int lengthThreshold = getResources().getInteger(
1390cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                    R.integer.snippet_length_before_tokenize);
1391cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            if (matched.line.length() > lengthThreshold) {
1392cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                return snippetize(matched.line, matched.startIndex, lengthThreshold);
1393cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            } else {
1394cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                return matched.line;
1395cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            }
1396cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1397cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1398cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // No match found.
1399cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        return null;
1400cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng    }
1401cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1402cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng    private String snippetize(String line, int matchIndex, int maxLength) {
1403cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Show up to maxLength characters. But we only show full tokens so show the last full token
1404cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // up to maxLength characters. So as many starting tokens as possible before trying ending
1405cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // tokens.
1406cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        int remainingLength = maxLength;
1407cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        int tempRemainingLength = remainingLength;
1408cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1409cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Start the end token after the matched query.
1410cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        int index = matchIndex;
1411cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        int endTokenIndex = index;
1412cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1413cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Find the match token first.
1414cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        while (index < line.length()) {
1415cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            if (!Character.isLetterOrDigit(line.charAt(index))) {
1416cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                endTokenIndex = index;
1417cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                remainingLength = tempRemainingLength;
1418cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                break;
1419cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            }
1420cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            tempRemainingLength--;
1421cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            index++;
1422cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1423cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1424cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Find as much content before the match.
1425cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        index = matchIndex - 1;
1426cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        tempRemainingLength = remainingLength;
1427cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        int startTokenIndex = matchIndex;
1428cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        while (index > -1 && tempRemainingLength > 0) {
1429cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            if (!Character.isLetterOrDigit(line.charAt(index))) {
1430cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                startTokenIndex = index;
1431cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                remainingLength = tempRemainingLength;
1432cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            }
1433cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            tempRemainingLength--;
1434cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            index--;
1435cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1436cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1437cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        index = endTokenIndex;
1438cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        tempRemainingLength = remainingLength;
1439cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Find remaining content at after match.
1440cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        while (index < line.length() && tempRemainingLength > 0) {
1441cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            if (!Character.isLetterOrDigit(line.charAt(index))) {
1442cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                endTokenIndex = index;
1443cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            }
1444cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            tempRemainingLength--;
1445cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            index++;
1446cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1447cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Append ellipse if there is content before or after.
1448cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        final StringBuilder sb = new StringBuilder();
1449cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        if (startTokenIndex > 0) {
1450cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            sb.append("...");
1451cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1452cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        sb.append(line.substring(startTokenIndex, endTokenIndex));
1453cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        if (endTokenIndex < line.length()) {
1454cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            sb.append("...");
1455cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1456cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        return sb.toString();
1457cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng    }
1458cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
145905897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng    private static final Pattern SPLIT_PATTERN = Pattern.compile(
146005897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng            "([\\w-\\.]+)@((?:[\\w]+\\.)+)([a-zA-Z]{2,4})|[\\w]+");
146105897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng
146205897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng    /**
146305897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     * Helper method for splitting a string into tokens.  The lists passed in are populated with
146405897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     * the
146505897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     * tokens and offsets into the content of each token.  The tokenization function parses e-mail
146605897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     * addresses as a single token; otherwise it splits on any non-alphanumeric character.
146705897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     *
146805897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     * @param content Content to split.
146905897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     * @return List of token strings.
147005897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     */
147105897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng    private static List<String> split(String content) {
147205897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        final Matcher matcher = SPLIT_PATTERN.matcher(content);
147305897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        final ArrayList<String> tokens = Lists.newArrayList();
147405897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        while (matcher.find()) {
147505897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng            tokens.add(matcher.group());
147605897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        }
147705897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        return tokens;
147805897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng    }
147905897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng
1480d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
14817a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner     * Shows data element.
1482d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1483d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void showData(Cursor cursor, int dataColumnIndex) {
1484d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        cursor.copyStringToBuffer(dataColumnIndex, mDataBuffer);
14857a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        setData(mDataBuffer.data, mDataBuffer.sizeCopied);
14867a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner    }
14877a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner
1488d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setActivatedStateSupported(boolean flag) {
1489d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        this.mActivatedStateSupported = flag;
1490d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1491d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1492fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee    public void setAdjustSelectionBoundsEnabled(boolean enabled) {
1493fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee        mAdjustSelectionBoundsEnabled = enabled;
1494fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee    }
1495fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee
1496d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
1497d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void requestLayout() {
1498d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // We will assume that once measured this will not need to resize
1499d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // itself, so there is no need to pass the layout request to the parent
1500d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // view (ListView).
1501d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        forceLayout();
1502d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1503d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1504d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setPhotoPosition(PhotoPosition photoPosition) {
1505d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mPhotoPosition = photoPosition;
1506d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1507d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1508d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public PhotoPosition getPhotoPosition() {
1509d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mPhotoPosition;
1510d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1511d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1512d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1513e05a0f5d375168585594fccf68a3ec60a88d4430Andrew Lee     * Set drawable resources directly for the drawable resource of the photo view.
151427330d80bb6575df2964112d34143125c8af9b78Yorke Lee     *
1515e05a0f5d375168585594fccf68a3ec60a88d4430Andrew Lee     * @param drawableId Id of drawable resource.
151627330d80bb6575df2964112d34143125c8af9b78Yorke Lee     */
1517e05a0f5d375168585594fccf68a3ec60a88d4430Andrew Lee    public void setDrawableResource(int drawableId) {
1518e05a0f5d375168585594fccf68a3ec60a88d4430Andrew Lee        ImageView photo = getPhotoView();
151927330d80bb6575df2964112d34143125c8af9b78Yorke Lee        photo.setScaleType(ImageView.ScaleType.CENTER);
1520e05a0f5d375168585594fccf68a3ec60a88d4430Andrew Lee        photo.setImageDrawable(getContext().getDrawable(drawableId));
15213181b8ffaa6af370268acee97903e98a6b94138fWenyi Wang        photo.setImageTintList(ColorStateList.valueOf(ContextCompat.getColor(
15223181b8ffaa6af370268acee97903e98a6b94138fWenyi Wang                getContext(), R.color.search_shortcut_icon_color)));
152327330d80bb6575df2964112d34143125c8af9b78Yorke Lee    }
152410349f190691f802b8935175dbf38bff74a8a703Yorke Lee
152510349f190691f802b8935175dbf38bff74a8a703Yorke Lee    @Override
152610349f190691f802b8935175dbf38bff74a8a703Yorke Lee    public boolean onTouchEvent(MotionEvent event) {
152710349f190691f802b8935175dbf38bff74a8a703Yorke Lee        final float x = event.getX();
152810349f190691f802b8935175dbf38bff74a8a703Yorke Lee        final float y = event.getY();
1529538e05b3bbde399f25ccf1aad251fca6d7f4d6b3Yorke Lee        // If the touch event's coordinates are not within the view's header, then delegate
1530538e05b3bbde399f25ccf1aad251fca6d7f4d6b3Yorke Lee        // to super.onTouchEvent so that regular view behavior is preserved. Otherwise, consume
1531538e05b3bbde399f25ccf1aad251fca6d7f4d6b3Yorke Lee        // and ignore the touch event.
1532bded9d078784569efef4aec2d636ce3f733601d7Yorke Lee        if (mBoundsWithoutHeader.contains((int) x, (int) y) || !pointIsInView(x, y)) {
153310349f190691f802b8935175dbf38bff74a8a703Yorke Lee            return super.onTouchEvent(event);
153410349f190691f802b8935175dbf38bff74a8a703Yorke Lee        } else {
153510349f190691f802b8935175dbf38bff74a8a703Yorke Lee            return true;
153610349f190691f802b8935175dbf38bff74a8a703Yorke Lee        }
153710349f190691f802b8935175dbf38bff74a8a703Yorke Lee    }
1538bded9d078784569efef4aec2d636ce3f733601d7Yorke Lee
1539bded9d078784569efef4aec2d636ce3f733601d7Yorke Lee    private final boolean pointIsInView(float localX, float localY) {
1540f7a205fdcb17161c454bee673cc2fce5b23d0760Sai Cheemalapati        return localX >= mLeftOffset && localX < mRightOffset
15413d7e2893cb55dc0f1bc4f7e731322973ee09bc1fYorke Lee                && localY >= 0 && localY < (getBottom() - getTop());
1542bded9d078784569efef4aec2d636ce3f733601d7Yorke Lee    }
1543d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng}
1544