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;
3273f41231df9868953047cbbcce529ee5687de7f2Walter Jangimport android.provider.ContactsContract.SearchSnippets;
333181b8ffaa6af370268acee97903e98a6b94138fWenyi Wangimport android.support.v4.content.ContextCompat;
34e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wangimport android.support.v4.graphics.drawable.DrawableCompat;
35d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.text.Spannable;
36d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.text.SpannableString;
37d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.text.TextUtils;
38d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.text.TextUtils.TruncateAt;
39d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.util.AttributeSet;
403bc19a3bb1ed23b03352fff6de69a89e763a315eSai Cheemalapatiimport android.util.TypedValue;
41d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.view.Gravity;
4210349f190691f802b8935175dbf38bff74a8a703Yorke Leeimport android.view.MotionEvent;
43d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.view.View;
44d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.view.ViewGroup;
45d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.widget.AbsListView.SelectionBoundsAdjuster;
464ad6cc6d88af85a069a948a27b344465619b5ad8Wenyi Wangimport android.widget.CheckBox;
47d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.widget.ImageView;
48d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.widget.ImageView.ScaleType;
49d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.widget.QuickContactBadge;
50d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.widget.TextView;
51d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
52d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport com.android.contacts.common.ContactPresenceIconUtil;
53d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport com.android.contacts.common.ContactStatusUtil;
54d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport com.android.contacts.common.R;
55e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wangimport com.android.contacts.common.compat.CompatUtils;
563abf10065b24373b3d6e46ed3c7f34af2b4639fbWenyi Wangimport com.android.contacts.common.compat.PhoneNumberUtilsCompat;
57a81953a2b1818066ef5e44817f374ac288bab343Christine Chenimport com.android.contacts.common.format.TextHighlighter;
58d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jangimport com.android.contacts.common.util.ContactDisplayUtils;
59cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Chengimport com.android.contacts.common.util.SearchUtil;
60864c67691b5a0169b5cbb91469d67d93e24ad9ebYorke Leeimport com.android.contacts.common.util.ViewUtil;
61864c67691b5a0169b5cbb91469d67d93e24ad9ebYorke Lee
6205897c8e016942e10f0ef6f0da02d339480d4748Chiao Chengimport com.google.common.collect.Lists;
6305897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng
6405897c8e016942e10f0ef6f0da02d339480d4748Chiao Chengimport java.util.ArrayList;
6505897c8e016942e10f0ef6f0da02d339480d4748Chiao Chengimport java.util.List;
669f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglioimport java.util.Locale;
6705897c8e016942e10f0ef6f0da02d339480d4748Chiao Chengimport java.util.regex.Matcher;
6805897c8e016942e10f0ef6f0da02d339480d4748Chiao Chengimport java.util.regex.Pattern;
69d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
70d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng/**
71d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * A custom view for an item in the contact list.
72d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * The view contains the contact's photo, a set of text views (for name, status, etc...) and
73d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * icons for presence and call.
74d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * The view uses no XML file for layout and all the measurements and layouts are done
75d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * in the onMeasure and onLayout methods.
76d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng *
77d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * The layout puts the contact's photo on the right side of the view, the call icon (if present)
78d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * to the left of the photo, the text lines are aligned to the left and the presence icon (if
79d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * present) is set to the left of the status line.
80d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng *
81d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * The layout also supports a header (used as a header of a group of contacts) that is above the
82d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * contact's data and a divider between contact view.
83d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng */
84d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
85d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengpublic class ContactListItemView extends ViewGroup
86d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        implements SelectionBoundsAdjuster {
87d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
88e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    private static final String TAG = "ContactListItemView";
89e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
90d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // Style values for layout and appearance
91d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // The initialized values are defaults if none is provided through xml.
92d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mPreferredHeight = 0;
93d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mGapBetweenImageAndText = 0;
94d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mGapBetweenLabelAndData = 0;
95d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mPresenceIconMargin = 4;
96d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mPresenceIconSize = 16;
97d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mTextIndent = 0;
987961175eb7b8b8d6f990bd8e510f59fe48c5ef4bAndrew Lee    private int mTextOffsetTop;
993bc19a3bb1ed23b03352fff6de69a89e763a315eSai Cheemalapati    private int mNameTextViewTextSize;
1001f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee    private int mHeaderWidth;
101d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private Drawable mActivatedBackgroundDrawable;
102e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    private int mVideoCallIconSize = 32;
103e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    private int mVideoCallIconMargin = 16;
104d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
105f7a205fdcb17161c454bee673cc2fce5b23d0760Sai Cheemalapati    // Set in onLayout. Represent left and right position of the View on the screen.
106f7a205fdcb17161c454bee673cc2fce5b23d0760Sai Cheemalapati    private int mLeftOffset;
107f7a205fdcb17161c454bee673cc2fce5b23d0760Sai Cheemalapati    private int mRightOffset;
108f7a205fdcb17161c454bee673cc2fce5b23d0760Sai Cheemalapati
109d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
110d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Used with {@link #mLabelView}, specifying the width ratio between label and data.
111d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
112d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mLabelViewWidthWeight = 3;
113d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
114d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Used with {@link #mDataView}, specifying the width ratio between label and data.
115d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
116d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mDataViewWidthWeight = 5;
117d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
118f99a990be713ed35afe64ba8133c5428816390c6Christine Chen    protected static class HighlightSequence {
119f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        private final int start;
120f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        private final int end;
121f99a990be713ed35afe64ba8133c5428816390c6Christine Chen
122f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        HighlightSequence(int start, int end) {
123f99a990be713ed35afe64ba8133c5428816390c6Christine Chen            this.start = start;
124f99a990be713ed35afe64ba8133c5428816390c6Christine Chen            this.end = end;
125f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        }
126f99a990be713ed35afe64ba8133c5428816390c6Christine Chen    }
127f99a990be713ed35afe64ba8133c5428816390c6Christine Chen
128f99a990be713ed35afe64ba8133c5428816390c6Christine Chen    private ArrayList<HighlightSequence> mNameHighlightSequence;
129f99a990be713ed35afe64ba8133c5428816390c6Christine Chen    private ArrayList<HighlightSequence> mNumberHighlightSequence;
130a81953a2b1818066ef5e44817f374ac288bab343Christine Chen
131a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    // Highlighting prefix for names.
132a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    private String mHighlightedPrefix;
133a81953a2b1818066ef5e44817f374ac288bab343Christine Chen
134d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
135e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     * Used to notify listeners when a video call icon is clicked.
136e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     */
137e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    private PhoneNumberListAdapter.Listener mPhoneNumberListAdapterListener;
138e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
139e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    /**
140e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     * Indicates whether to show the "video call" icon, used to initiate a video call.
141e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     */
142e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    private boolean mShowVideoCallIcon = false;
143e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
144e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    /**
145e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     * Indicates whether the view should leave room for the "video call" icon.
146e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     */
147e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    private boolean mSupportVideoCallIcon = false;
148e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
149e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    /**
150d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Where to put contact photo. This affects the other Views' layout or look-and-feel.
1519f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio     *
1529f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio     * TODO: replace enum with int constants
153d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
154d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public enum PhotoPosition {
155d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        LEFT,
156d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        RIGHT
157d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1589f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio
1599f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio    static public final PhotoPosition getDefaultPhotoPosition(boolean opposite) {
1609f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        final Locale locale = Locale.getDefault();
1619f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        final int layoutDirection = TextUtils.getLayoutDirectionFromLocale(locale);
1629f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        switch (layoutDirection) {
1639f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            case View.LAYOUT_DIRECTION_RTL:
164a9950433dc469d24b314204075a6250d2410e01bAndrew Lee                return (opposite ? PhotoPosition.LEFT : PhotoPosition.RIGHT);
1659f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            case View.LAYOUT_DIRECTION_LTR:
1669f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            default:
167a9950433dc469d24b314204075a6250d2410e01bAndrew Lee                return (opposite ? PhotoPosition.RIGHT : PhotoPosition.LEFT);
1689f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        }
1699f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio    }
1709f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio
1719f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio    private PhotoPosition mPhotoPosition = getDefaultPhotoPosition(false /* normal/non opposite */);
172d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
173d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // Header layout data
174d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mHeaderTextView;
1751f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee    private boolean mIsSectionHeaderEnabled;
176d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
177d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // The views inside the contact view
178d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mQuickContactEnabled = true;
179d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private QuickContactBadge mQuickContact;
180d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private ImageView mPhotoView;
181d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mNameTextView;
182d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mPhoneticNameTextView;
183d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mLabelView;
184d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mDataView;
185d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mSnippetView;
186d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TextView mStatusView;
187d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private ImageView mPresenceIcon;
1884ad6cc6d88af85a069a948a27b344465619b5ad8Wenyi Wang    private CheckBox mCheckBox;
189e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    private ImageView mVideoCallIcon;
190d19d35ef8347038f5296ed7020cab79396874937Victor Chang    private ImageView mWorkProfileIcon;
191d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
192d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private ColorStateList mSecondaryTextColor;
193d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
194d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mDefaultPhotoViewSize = 0;
195d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
196d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Can be effective even when {@link #mPhotoView} is null, as we want to have horizontal padding
197d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * to align other data in this View.
198d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
199d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mPhotoViewWidth;
200d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
201d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Can be effective even when {@link #mPhotoView} is null, as we want to have vertical padding.
202d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
203d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mPhotoViewHeight;
204d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
205d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
206d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Only effective when {@link #mPhotoView} is null.
207d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * When true all the Views on the right side of the photo should have horizontal padding on
208d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * those left assuming there is a photo.
209d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
210d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mKeepHorizontalPaddingForPhotoView;
211d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
212d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Only effective when {@link #mPhotoView} is null.
213d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
214d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mKeepVerticalPaddingForPhotoView;
215d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
216d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
217d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * True when {@link #mPhotoViewWidth} and {@link #mPhotoViewHeight} are ready for being used.
218d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * False indicates those values should be updated before being used in position calculation.
219d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
220d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mPhotoViewWidthAndHeightAreReady = false;
221d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
222d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mNameTextViewHeight;
22358a793ee1253f8f46dd7f754a51f61a6bbcdce60Andrew Lee    private int mNameTextViewTextColor = Color.BLACK;
224d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mPhoneticNameTextViewHeight;
225d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mLabelViewHeight;
226d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mDataViewHeight;
227d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mSnippetTextViewHeight;
228d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mStatusTextViewHeight;
22908901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell    private int mCheckBoxHeight;
23008901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell    private int mCheckBoxWidth;
231d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
232d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // Holds Math.max(mLabelTextViewHeight, mDataViewHeight), assuming Label and Data share the
233d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // same row.
234d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mLabelAndDataViewMaxHeight;
235d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
236d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // TODO: some TextView fields are using CharArrayBuffer while some are not. Determine which is
237d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // more efficient for each case or in general, and simplify the whole implementation.
238d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // Note: if we're sure MARQUEE will be used every time, there's no reason to use
239d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // CharArrayBuffer, since MARQUEE requires Span and thus we need to copy characters inside the
240d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // buffer to Spannable once, while CharArrayBuffer is for directly applying char array to
241d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // TextView without any modification.
242d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private final CharArrayBuffer mDataBuffer = new CharArrayBuffer(128);
243d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private final CharArrayBuffer mPhoneticNameBuffer = new CharArrayBuffer(128);
244d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
245d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mActivatedStateSupported;
246fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee    private boolean mAdjustSelectionBoundsEnabled = true;
247d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
248d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private Rect mBoundsWithoutHeader = new Rect();
249d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
250d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /** A helper used to highlight a prefix in a text field. */
251a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    private final TextHighlighter mTextHighlighter;
252d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private CharSequence mUnknownNameText;
253e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    private int mPosition;
254d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
255d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public ContactListItemView(Context context) {
256d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        super(context);
257d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
25842210256d3d584783ac2fb2742088ce57d9da766Yorke Lee        mTextHighlighter = new TextHighlighter(Typeface.BOLD);
259bb67024ef64a7853f5ec320652d80f0cdf7b660fYorke Lee        mNameHighlightSequence = new ArrayList<HighlightSequence>();
260bb67024ef64a7853f5ec320652d80f0cdf7b660fYorke Lee        mNumberHighlightSequence = new ArrayList<HighlightSequence>();
261d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
262d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
263e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    public ContactListItemView(Context context, AttributeSet attrs, boolean supportVideoCallIcon) {
264e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        this(context, attrs);
265e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
266e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        mSupportVideoCallIcon = supportVideoCallIcon;
267e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    }
268e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
269d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public ContactListItemView(Context context, AttributeSet attrs) {
270d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        super(context, attrs);
271d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
27225527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee        TypedArray a;
27325527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee
27425527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee        if (R.styleable.ContactListItemView != null) {
27525527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            // Read all style values
27625527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            a = getContext().obtainStyledAttributes(attrs, R.styleable.ContactListItemView);
27725527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mPreferredHeight = a.getDimensionPixelSize(
27825527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_height, mPreferredHeight);
27925527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mActivatedBackgroundDrawable = a.getDrawable(
28025527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_activated_background);
28125527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee
28225527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mGapBetweenImageAndText = a.getDimensionPixelOffset(
28325527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_gap_between_image_and_text,
28425527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    mGapBetweenImageAndText);
28525527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mGapBetweenLabelAndData = a.getDimensionPixelOffset(
28625527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_gap_between_label_and_data,
28725527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    mGapBetweenLabelAndData);
28825527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mPresenceIconMargin = a.getDimensionPixelOffset(
28925527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_presence_icon_margin,
29025527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    mPresenceIconMargin);
29125527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mPresenceIconSize = a.getDimensionPixelOffset(
29225527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_presence_icon_size,
29325527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    mPresenceIconSize);
29425527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mDefaultPhotoViewSize = a.getDimensionPixelOffset(
29525527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_photo_size, mDefaultPhotoViewSize);
29625527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mTextIndent = a.getDimensionPixelOffset(
29725527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_text_indent, mTextIndent);
29825527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mTextOffsetTop = a.getDimensionPixelOffset(
29925527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_text_offset_top, mTextOffsetTop);
30025527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mDataViewWidthWeight = a.getInteger(
30125527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_data_width_weight,
30225527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    mDataViewWidthWeight);
30325527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mLabelViewWidthWeight = a.getInteger(
30425527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_label_width_weight,
30525527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    mLabelViewWidthWeight);
30625527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mNameTextViewTextColor = a.getColor(
30725527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_name_text_color,
30825527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    mNameTextViewTextColor);
30925527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mNameTextViewTextSize = (int) a.getDimension(
31025527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    R.styleable.ContactListItemView_list_item_name_text_size,
31125527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    (int) getResources().getDimension(R.dimen.contact_browser_list_item_text_size));
312e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            mVideoCallIconSize = a.getDimensionPixelOffset(
313e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                    R.styleable.ContactListItemView_list_item_video_call_icon_size,
314e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                    mVideoCallIconSize);
315e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            mVideoCallIconMargin = a.getDimensionPixelOffset(
316e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                    R.styleable.ContactListItemView_list_item_video_call_icon_margin,
317e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                    mVideoCallIconMargin);
318e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
31925527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee
32025527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            setPaddingRelative(
32125527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    a.getDimensionPixelOffset(
32225527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                            R.styleable.ContactListItemView_list_item_padding_left, 0),
32325527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    a.getDimensionPixelOffset(
32425527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                            R.styleable.ContactListItemView_list_item_padding_top, 0),
32525527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    a.getDimensionPixelOffset(
32625527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                            R.styleable.ContactListItemView_list_item_padding_right, 0),
32725527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                    a.getDimensionPixelOffset(
32825527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee                            R.styleable.ContactListItemView_list_item_padding_bottom, 0));
32925527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee
33025527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            a.recycle();
33125527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee        }
332d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
33342210256d3d584783ac2fb2742088ce57d9da766Yorke Lee        mTextHighlighter = new TextHighlighter(Typeface.BOLD);
33442210256d3d584783ac2fb2742088ce57d9da766Yorke Lee
33525527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee        if (R.styleable.Theme != null) {
33625527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            a = getContext().obtainStyledAttributes(R.styleable.Theme);
33725527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            mSecondaryTextColor = a.getColorStateList(R.styleable.Theme_android_textColorSecondary);
33825527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee            a.recycle();
33925527b9fe191063927e211bcf86d5cd26ab6b67aYorke Lee        }
340d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
3411f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee        mHeaderWidth =
3421f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee                getResources().getDimensionPixelSize(R.dimen.contact_list_section_header_width);
3431f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee
344d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mActivatedBackgroundDrawable != null) {
345d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mActivatedBackgroundDrawable.setCallback(this);
346d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
347f99a990be713ed35afe64ba8133c5428816390c6Christine Chen
348f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        mNameHighlightSequence = new ArrayList<HighlightSequence>();
349f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        mNumberHighlightSequence = new ArrayList<HighlightSequence>();
35053c7dc1e9691b5b427395642a4274d37a1a15bb4Yorke Lee
35153c7dc1e9691b5b427395642a4274d37a1a15bb4Yorke Lee        setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE);
352d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
353d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
354d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setUnknownNameText(CharSequence unknownNameText) {
355d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mUnknownNameText = unknownNameText;
356d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
357d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
358d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setQuickContactEnabled(boolean flag) {
359d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mQuickContactEnabled = flag;
360d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
361d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
362e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    /**
363e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     * Sets whether the video calling icon is shown.  For the video calling icon to be shown,
364e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     * {@link #mSupportVideoCallIcon} must be {@code true}.
365e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     *
366e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     * @param showVideoCallIcon {@code true} if the video calling icon is shown, {@code false}
367e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     *      otherwise.
368e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     * @param listener Listener to notify when the video calling icon is clicked.
369e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     * @param position The position in the adapater of the video calling icon.
370e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     */
371e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    public void setShowVideoCallIcon(boolean showVideoCallIcon,
372e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            PhoneNumberListAdapter.Listener listener, int position) {
373e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        mShowVideoCallIcon = showVideoCallIcon;
374e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        mPhoneNumberListAdapterListener = listener;
375e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        mPosition = position;
376e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
377e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        if (mShowVideoCallIcon) {
378e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            if (mVideoCallIcon == null) {
379e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                mVideoCallIcon = new ImageView(getContext());
380e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                addView(mVideoCallIcon);
381e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            }
382e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            mVideoCallIcon.setContentDescription(getContext().getString(
383e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                    R.string.description_search_video_call));
384e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            mVideoCallIcon.setImageResource(R.drawable.ic_search_video_call);
385e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            mVideoCallIcon.setScaleType(ScaleType.CENTER);
386e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            mVideoCallIcon.setVisibility(View.VISIBLE);
387e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            mVideoCallIcon.setOnClickListener(new OnClickListener() {
388e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                @Override
389e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                public void onClick(View v) {
390e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                    // Inform the adapter that the video calling icon was clicked.
391e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                    if (mPhoneNumberListAdapterListener != null) {
392e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                        mPhoneNumberListAdapterListener.onVideoCallIconClicked(mPosition);
393e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                    }
394e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                }
395e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            });
396e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        } else {
397e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            if (mVideoCallIcon != null) {
398e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                mVideoCallIcon.setVisibility(View.GONE);
399e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            }
400e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        }
401e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    }
402e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
403e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    /**
404e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     * Sets whether the view supports a video calling icon.  This is independent of whether the view
405e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     * is actually showing an icon.  Support for the video calling icon ensures that the layout
406e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     * leaves space for the video icon, should it be shown.
407e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     *
408e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     * @param supportVideoCallIcon {@code true} if the video call icon is supported, {@code false}
409e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     *      otherwise.
410e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn     */
411e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    public void setSupportVideoCallIcon(boolean supportVideoCallIcon) {
412e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        mSupportVideoCallIcon = supportVideoCallIcon;
413e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    }
414e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
415d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
416d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
417d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // We will match parent's width and wrap content vertically, but make sure
418d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // height is no less than listPreferredItemHeight.
419d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int specWidth = resolveSize(0, widthMeasureSpec);
420f4fcd3def28e5b1168f5160e476c05ad69339adcAndrew Lee        final int preferredHeight = mPreferredHeight;
421d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
422d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mNameTextViewHeight = 0;
423d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mPhoneticNameTextViewHeight = 0;
424d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mLabelViewHeight = 0;
425d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mDataViewHeight = 0;
426d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mLabelAndDataViewMaxHeight = 0;
427d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mSnippetTextViewHeight = 0;
428d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mStatusTextViewHeight = 0;
42908901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        mCheckBoxWidth = 0;
43008901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        mCheckBoxHeight = 0;
431d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
432d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        ensurePhotoViewSize();
433d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
434d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Width each TextView is able to use.
435ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee        int effectiveWidth;
436d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // All the other Views will honor the photo, so available width for them may be shrunk.
437d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mPhotoViewWidth > 0 || mKeepHorizontalPaddingForPhotoView) {
438d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            effectiveWidth = specWidth - getPaddingLeft() - getPaddingRight()
439d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    - (mPhotoViewWidth + mGapBetweenImageAndText);
440d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
441d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            effectiveWidth = specWidth - getPaddingLeft() - getPaddingRight();
442d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
443d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
444ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee        if (mIsSectionHeaderEnabled) {
445ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee            effectiveWidth -= mHeaderWidth + mGapBetweenImageAndText;
446ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee        }
447ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee
448e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        if (mSupportVideoCallIcon) {
449e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            effectiveWidth -= (mVideoCallIconSize + mVideoCallIconMargin);
450e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        }
451e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
452d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Go over all visible text views and measure actual width of each of them.
453d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Also calculate their heights to get the total height for this entire view.
454d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
45508901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        if (isVisible(mCheckBox)) {
45608901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            mCheckBox.measure(
45708901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
45808901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
45908901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            mCheckBoxWidth = mCheckBox.getMeasuredWidth();
46008901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            mCheckBoxHeight = mCheckBox.getMeasuredHeight();
46108901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            effectiveWidth -= mCheckBoxWidth + mGapBetweenImageAndText;
46208901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        }
46308901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell
464d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mNameTextView)) {
46590fbbae42d4628b18e78434e7de13254099b229ePaul Soulos            // Calculate width for name text - this parallels similar measurement in onLayout.
466d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            int nameTextWidth = effectiveWidth;
467d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mPhotoPosition != PhotoPosition.LEFT) {
468d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                nameTextWidth -= mTextIndent;
469d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
470d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView.measure(
471d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(nameTextWidth, MeasureSpec.EXACTLY),
472d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
473d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextViewHeight = mNameTextView.getMeasuredHeight();
474d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
475d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
476d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mPhoneticNameTextView)) {
477d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.measure(
478d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(effectiveWidth, MeasureSpec.EXACTLY),
479d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
480d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextViewHeight = mPhoneticNameTextView.getMeasuredHeight();
481d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
482d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
483d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // If both data (phone number/email address) and label (type like "MOBILE") are quite long,
484d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // we should ellipsize both using appropriate ratio.
485d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int dataWidth;
486d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int labelWidth;
487d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mDataView)) {
488d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (isVisible(mLabelView)) {
489d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                final int totalWidth = effectiveWidth - mGapBetweenLabelAndData;
490d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                dataWidth = ((totalWidth * mDataViewWidthWeight)
491d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        / (mDataViewWidthWeight + mLabelViewWidthWeight));
492d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                labelWidth = ((totalWidth * mLabelViewWidthWeight) /
493d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        (mDataViewWidthWeight + mLabelViewWidthWeight));
494d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            } else {
495d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                dataWidth = effectiveWidth;
496d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                labelWidth = 0;
497d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
498d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
499d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            dataWidth = 0;
500d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (isVisible(mLabelView)) {
501d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                labelWidth = effectiveWidth;
502d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            } else {
503d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                labelWidth = 0;
504d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
505d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
506d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
507d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mDataView)) {
508d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataView.measure(MeasureSpec.makeMeasureSpec(dataWidth, MeasureSpec.EXACTLY),
509d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
510d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataViewHeight = mDataView.getMeasuredHeight();
511d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
512d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
513d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mLabelView)) {
514e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            mLabelView.measure(MeasureSpec.makeMeasureSpec(labelWidth, MeasureSpec.AT_MOST),
515d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
516d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mLabelViewHeight = mLabelView.getMeasuredHeight();
517d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
518d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mLabelAndDataViewMaxHeight = Math.max(mLabelViewHeight, mDataViewHeight);
519d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
520d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mSnippetView)) {
521d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.measure(
522d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(effectiveWidth, MeasureSpec.EXACTLY),
523d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
524d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetTextViewHeight = mSnippetView.getMeasuredHeight();
525d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
526d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
527d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Status view height is the biggest of the text view and the presence icon
528d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mPresenceIcon)) {
529d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPresenceIcon.measure(
530d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(mPresenceIconSize, MeasureSpec.EXACTLY),
531d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(mPresenceIconSize, MeasureSpec.EXACTLY));
532d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusTextViewHeight = mPresenceIcon.getMeasuredHeight();
533d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
534d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
535e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        if (mSupportVideoCallIcon && isVisible(mVideoCallIcon)) {
536e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            mVideoCallIcon.measure(
537e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                    MeasureSpec.makeMeasureSpec(mVideoCallIconSize, MeasureSpec.EXACTLY),
538e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                    MeasureSpec.makeMeasureSpec(mVideoCallIconSize, MeasureSpec.EXACTLY));
539e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        }
540e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
541d19d35ef8347038f5296ed7020cab79396874937Victor Chang        if (isVisible(mWorkProfileIcon)) {
542d19d35ef8347038f5296ed7020cab79396874937Victor Chang            mWorkProfileIcon.measure(
543d19d35ef8347038f5296ed7020cab79396874937Victor Chang                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
544d19d35ef8347038f5296ed7020cab79396874937Victor Chang                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
545d19d35ef8347038f5296ed7020cab79396874937Victor Chang            mNameTextViewHeight =
546d19d35ef8347038f5296ed7020cab79396874937Victor Chang                    Math.max(mNameTextViewHeight, mWorkProfileIcon.getMeasuredHeight());
547d19d35ef8347038f5296ed7020cab79396874937Victor Chang        }
548d19d35ef8347038f5296ed7020cab79396874937Victor Chang
549d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mStatusView)) {
550d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Presence and status are in a same row, so status will be affected by icon size.
551d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            final int statusWidth;
552d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (isVisible(mPresenceIcon)) {
553d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                statusWidth = (effectiveWidth - mPresenceIcon.getMeasuredWidth()
554d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        - mPresenceIconMargin);
555d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            } else {
556d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                statusWidth = effectiveWidth;
557d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
558d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView.measure(MeasureSpec.makeMeasureSpec(statusWidth, MeasureSpec.EXACTLY),
559d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
560d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusTextViewHeight =
561d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    Math.max(mStatusTextViewHeight, mStatusView.getMeasuredHeight());
562d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
563d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
564d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Calculate height including padding.
565d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int height = (mNameTextViewHeight + mPhoneticNameTextViewHeight +
566d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelAndDataViewMaxHeight +
567d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mSnippetTextViewHeight + mStatusTextViewHeight);
568d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
569d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Make sure the height is at least as high as the photo
570d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        height = Math.max(height, mPhotoViewHeight + getPaddingBottom() + getPaddingTop());
571d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
572d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Make sure height is at least the preferred height
573d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        height = Math.max(height, preferredHeight);
574d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
5751f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee        // Measure the header if it is visible.
5761f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee        if (mHeaderTextView != null && mHeaderTextView.getVisibility() == VISIBLE) {
577d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mHeaderTextView.measure(
5781f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee                    MeasureSpec.makeMeasureSpec(mHeaderWidth, MeasureSpec.EXACTLY),
5796fdf16941587a222f554482fb72531783a924b6eAndrew Lee                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
580d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
581d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
582d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        setMeasuredDimension(specWidth, height);
583d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
584d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
585d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
586d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
587d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int height = bottom - top;
588d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int width = right - left;
589d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
590d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Determine the vertical bounds by laying out the header first.
591d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int topBound = 0;
592d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int bottomBound = height;
593d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int leftBound = getPaddingLeft();
594d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int rightBound = width - getPaddingRight();
595d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
596864c67691b5a0169b5cbb91469d67d93e24ad9ebYorke Lee        final boolean isLayoutRtl = ViewUtil.isViewLayoutRtl(this);
59709f15e70e86d92ae0f4c15a726b777f170845a3cYorke Lee
5981f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee        // Put the section header on the left side of the contact view.
5991f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee        if (mIsSectionHeaderEnabled) {
6001f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee            if (mHeaderTextView != null) {
6016fdf16941587a222f554482fb72531783a924b6eAndrew Lee                int headerHeight = mHeaderTextView.getMeasuredHeight();
6026fdf16941587a222f554482fb72531783a924b6eAndrew Lee                int headerTopBound = (bottomBound + topBound - headerHeight) / 2 + mTextOffsetTop;
6036fdf16941587a222f554482fb72531783a924b6eAndrew Lee
6041f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee                mHeaderTextView.layout(
6051f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee                        isLayoutRtl ? rightBound - mHeaderWidth : leftBound,
6066fdf16941587a222f554482fb72531783a924b6eAndrew Lee                        headerTopBound,
6071f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee                        isLayoutRtl ? rightBound : leftBound + mHeaderWidth,
6086fdf16941587a222f554482fb72531783a924b6eAndrew Lee                        headerTopBound + headerHeight);
6091f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee            }
6101f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee            if (isLayoutRtl) {
6111f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee                rightBound -= mHeaderWidth;
6121f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee            } else {
6131f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee                leftBound += mHeaderWidth;
6141f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee            }
615d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
616d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
617f7a205fdcb17161c454bee673cc2fce5b23d0760Sai Cheemalapati        mBoundsWithoutHeader.set(left + leftBound, topBound, left + rightBound, bottomBound);
618f7a205fdcb17161c454bee673cc2fce5b23d0760Sai Cheemalapati        mLeftOffset = left + leftBound;
619f7a205fdcb17161c454bee673cc2fce5b23d0760Sai Cheemalapati        mRightOffset = left + rightBound;
620ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee        if (mIsSectionHeaderEnabled) {
621ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee            if (isLayoutRtl) {
622ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee                rightBound -= mGapBetweenImageAndText;
623ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee            } else {
624ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee                leftBound += mGapBetweenImageAndText;
625ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee            }
626ceb851d9c2d5c73bdd9c60ca47be0902516636aaAndrew Lee        }
627d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
628d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mActivatedStateSupported && isActivated()) {
629d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mActivatedBackgroundDrawable.setBounds(mBoundsWithoutHeader);
630d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
631d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
63208901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        if (isVisible(mCheckBox)) {
63308901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            final int photoTop = topBound + (bottomBound - topBound - mCheckBoxHeight) / 2;
63408901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            if (mPhotoPosition == PhotoPosition.LEFT) {
63508901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                mCheckBox.layout(rightBound - mCheckBoxWidth,
63608901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        photoTop,
63708901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        rightBound,
63808901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        photoTop + mCheckBoxHeight);
63908901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            } else {
64008901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                mCheckBox.layout(leftBound,
64108901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        photoTop,
64208901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        leftBound + mCheckBoxWidth,
64308901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        photoTop + mCheckBoxHeight);
64408901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            }
64508901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        }
64608901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell
647d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final View photoView = mQuickContact != null ? mQuickContact : mPhotoView;
648d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mPhotoPosition == PhotoPosition.LEFT) {
649d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Photo is the left most view. All the other Views should on the right of the photo.
650d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (photoView != null) {
651d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                // Center the photo vertically
652d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                final int photoTop = topBound + (bottomBound - topBound - mPhotoViewHeight) / 2;
653d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                photoView.layout(
654d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        leftBound,
655d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        photoTop,
656d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        leftBound + mPhotoViewWidth,
657d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        photoTop + mPhotoViewHeight);
658d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                leftBound += mPhotoViewWidth + mGapBetweenImageAndText;
659d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            } else if (mKeepHorizontalPaddingForPhotoView) {
660d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                // Draw nothing but keep the padding.
661d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                leftBound += mPhotoViewWidth + mGapBetweenImageAndText;
662d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
663d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
664d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Photo is the right most view. Right bound should be adjusted that way.
665d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (photoView != null) {
666d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                // Center the photo vertically
667d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                final int photoTop = topBound + (bottomBound - topBound - mPhotoViewHeight) / 2;
668d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                photoView.layout(
669d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        rightBound - mPhotoViewWidth,
670d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        photoTop,
671d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        rightBound,
672d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        photoTop + mPhotoViewHeight);
673d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                rightBound -= (mPhotoViewWidth + mGapBetweenImageAndText);
6749f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            } else if (mKeepHorizontalPaddingForPhotoView) {
6759f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                // Draw nothing but keep the padding.
6769f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                rightBound -= (mPhotoViewWidth + mGapBetweenImageAndText);
677d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
678d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
679d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Add indent between left-most padding and texts.
680d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            leftBound += mTextIndent;
681d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
682d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
683e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        if (mSupportVideoCallIcon) {
684e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            // Place the video call button at the end of the list (e.g. take into account RTL mode).
685e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            if (isVisible(mVideoCallIcon)) {
686e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                // Center the video icon vertically
687e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                final int videoIconTop = topBound +
688e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                        (bottomBound - topBound - mVideoCallIconSize) / 2;
689e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
690e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                if (!isLayoutRtl) {
691e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                    // When photo is on left, video icon is placed on the right edge.
692e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                    mVideoCallIcon.layout(rightBound - mVideoCallIconSize,
693e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                            videoIconTop,
694e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                            rightBound,
695e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                            videoIconTop + mVideoCallIconSize);
696e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                } else {
697e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                    // When photo is on right, video icon is placed on the left edge.
698e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                    mVideoCallIcon.layout(leftBound,
699e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                            videoIconTop,
700e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                            leftBound + mVideoCallIconSize,
701e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                            videoIconTop + mVideoCallIconSize);
702e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                }
703e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            }
704e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
705e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            if (mPhotoPosition == PhotoPosition.LEFT) {
706e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                rightBound -= (mVideoCallIconSize + mVideoCallIconMargin);
707e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            } else {
708e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                leftBound += mVideoCallIconSize + mVideoCallIconMargin;
709e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            }
710e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        }
711e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
712e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
7137961175eb7b8b8d6f990bd8e510f59fe48c5ef4bAndrew Lee        // Center text vertically, then apply the top offset.
714d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int totalTextHeight = mNameTextViewHeight + mPhoneticNameTextViewHeight +
715d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelAndDataViewMaxHeight + mSnippetTextViewHeight + mStatusTextViewHeight;
7167961175eb7b8b8d6f990bd8e510f59fe48c5ef4bAndrew Lee        int textTopBound = (bottomBound + topBound - totalTextHeight) / 2 + mTextOffsetTop;
717d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
718d19d35ef8347038f5296ed7020cab79396874937Victor Chang        // Work Profile icon align top
719d19d35ef8347038f5296ed7020cab79396874937Victor Chang        int workProfileIconWidth = 0;
720d19d35ef8347038f5296ed7020cab79396874937Victor Chang        if (isVisible(mWorkProfileIcon)) {
721d19d35ef8347038f5296ed7020cab79396874937Victor Chang            workProfileIconWidth = mWorkProfileIcon.getMeasuredWidth();
722d19d35ef8347038f5296ed7020cab79396874937Victor Chang            final int distanceFromEnd = mCheckBoxWidth > 0
723d19d35ef8347038f5296ed7020cab79396874937Victor Chang                    ? mCheckBoxWidth + mGapBetweenImageAndText : 0;
724d19d35ef8347038f5296ed7020cab79396874937Victor Chang            if (mPhotoPosition == PhotoPosition.LEFT) {
725d19d35ef8347038f5296ed7020cab79396874937Victor Chang                // When photo is on left, label is placed on the right edge of the list item.
726d19d35ef8347038f5296ed7020cab79396874937Victor Chang                mWorkProfileIcon.layout(rightBound - workProfileIconWidth - distanceFromEnd,
727d19d35ef8347038f5296ed7020cab79396874937Victor Chang                        textTopBound,
728d19d35ef8347038f5296ed7020cab79396874937Victor Chang                        rightBound - distanceFromEnd,
729d19d35ef8347038f5296ed7020cab79396874937Victor Chang                        textTopBound + mNameTextViewHeight);
730d19d35ef8347038f5296ed7020cab79396874937Victor Chang            } else {
731d19d35ef8347038f5296ed7020cab79396874937Victor Chang                // When photo is on right, label is placed on the left of data view.
732d19d35ef8347038f5296ed7020cab79396874937Victor Chang                mWorkProfileIcon.layout(leftBound + distanceFromEnd,
733d19d35ef8347038f5296ed7020cab79396874937Victor Chang                        textTopBound,
734d19d35ef8347038f5296ed7020cab79396874937Victor Chang                        leftBound + workProfileIconWidth + distanceFromEnd,
735d19d35ef8347038f5296ed7020cab79396874937Victor Chang                        textTopBound + mNameTextViewHeight);
736d19d35ef8347038f5296ed7020cab79396874937Victor Chang            }
737d19d35ef8347038f5296ed7020cab79396874937Victor Chang        }
738d19d35ef8347038f5296ed7020cab79396874937Victor Chang
739d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Layout all text view and presence icon
740d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Put name TextView first
741d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mNameTextView)) {
742d19d35ef8347038f5296ed7020cab79396874937Victor Chang            final int distanceFromEnd = workProfileIconWidth
743d19d35ef8347038f5296ed7020cab79396874937Victor Chang                    + (mCheckBoxWidth > 0 ? mCheckBoxWidth + mGapBetweenImageAndText : 0);
74408901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            if (mPhotoPosition == PhotoPosition.LEFT) {
74508901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                mNameTextView.layout(leftBound,
74608901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        textTopBound,
74708901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        rightBound - distanceFromEnd,
74808901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        textTopBound + mNameTextViewHeight);
74908901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            } else {
75008901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                mNameTextView.layout(leftBound + distanceFromEnd,
75108901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        textTopBound,
75208901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        rightBound,
75308901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell                        textTopBound + mNameTextViewHeight);
75408901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            }
755d19d35ef8347038f5296ed7020cab79396874937Victor Chang        }
756d19d35ef8347038f5296ed7020cab79396874937Victor Chang
757d19d35ef8347038f5296ed7020cab79396874937Victor Chang        if (isVisible(mNameTextView) || isVisible(mWorkProfileIcon)) {
758d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textTopBound += mNameTextViewHeight;
759d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
760d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
761d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Presence and status
7629f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        if (isLayoutRtl) {
7639f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            int statusRightBound = rightBound;
7649f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            if (isVisible(mPresenceIcon)) {
7659f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                int iconWidth = mPresenceIcon.getMeasuredWidth();
7669f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                mPresenceIcon.layout(
7679f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        rightBound - iconWidth,
7689f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound,
7699f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        rightBound,
7709f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound + mStatusTextViewHeight);
7719f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                statusRightBound -= (iconWidth + mPresenceIconMargin);
7729f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            }
773d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
7749f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            if (isVisible(mStatusView)) {
7759f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                mStatusView.layout(leftBound,
7769f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound,
7779f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        statusRightBound,
7789f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound + mStatusTextViewHeight);
7799f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            }
7809f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio        } else {
7819f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            int statusLeftBound = leftBound;
7829f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            if (isVisible(mPresenceIcon)) {
7839f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                int iconWidth = mPresenceIcon.getMeasuredWidth();
7849f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                mPresenceIcon.layout(
7859f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        leftBound,
7869f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound,
7879f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        leftBound + iconWidth,
7889f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound + mStatusTextViewHeight);
7899f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                statusLeftBound += (iconWidth + mPresenceIconMargin);
7909f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            }
7919f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio
7929f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            if (isVisible(mStatusView)) {
7939f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                mStatusView.layout(statusLeftBound,
7949f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound,
7959f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        rightBound,
7969f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio                        textTopBound + mStatusTextViewHeight);
7979f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            }
798d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
799d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
800d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mStatusView) || isVisible(mPresenceIcon)) {
801d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textTopBound += mStatusTextViewHeight;
802d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
803d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
804d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Rest of text views
805d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int dataLeftBound = leftBound;
806d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mPhoneticNameTextView)) {
807d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.layout(leftBound,
808d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    textTopBound,
809d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    rightBound,
810d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    textTopBound + mPhoneticNameTextViewHeight);
811d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textTopBound += mPhoneticNameTextViewHeight;
812d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
813d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
814d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Label and Data align bottom.
815d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mLabelView)) {
816e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            if (!isLayoutRtl) {
817e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                mLabelView.layout(dataLeftBound,
818d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        textTopBound + mLabelAndDataViewMaxHeight - mLabelViewHeight,
819d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        rightBound,
820d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        textTopBound + mLabelAndDataViewMaxHeight);
821e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                dataLeftBound += mLabelView.getMeasuredWidth() + mGapBetweenLabelAndData;
822d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            } else {
823d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                dataLeftBound = leftBound + mLabelView.getMeasuredWidth();
824e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                mLabelView.layout(rightBound - mLabelView.getMeasuredWidth(),
825d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        textTopBound + mLabelAndDataViewMaxHeight - mLabelViewHeight,
826e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                        rightBound,
827d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        textTopBound + mLabelAndDataViewMaxHeight);
828e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                rightBound -= (mLabelView.getMeasuredWidth() + mGapBetweenLabelAndData);
829d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
830d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
831d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
832d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mDataView)) {
833e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            if (!isLayoutRtl) {
834e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                mDataView.layout(dataLeftBound,
835e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                        textTopBound + mLabelAndDataViewMaxHeight - mDataViewHeight,
836e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                        rightBound,
837e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                        textTopBound + mLabelAndDataViewMaxHeight);
838e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            } else {
839e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                mDataView.layout(rightBound - mDataView.getMeasuredWidth(),
840e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                        textTopBound + mLabelAndDataViewMaxHeight - mDataViewHeight,
841e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                        rightBound,
842e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                        textTopBound + mLabelAndDataViewMaxHeight);
843e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            }
844d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
845d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mLabelView) || isVisible(mDataView)) {
846d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textTopBound += mLabelAndDataViewMaxHeight;
847d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
848d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
849d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isVisible(mSnippetView)) {
850d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.layout(leftBound,
851d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    textTopBound,
852d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    rightBound,
853d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    textTopBound + mSnippetTextViewHeight);
854d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
855d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
856d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
857d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
858d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void adjustListItemSelectionBounds(Rect bounds) {
859fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee        if (mAdjustSelectionBoundsEnabled) {
860fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee            bounds.top += mBoundsWithoutHeader.top;
861fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee            bounds.bottom = bounds.top + mBoundsWithoutHeader.height();
862fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee            bounds.left = mBoundsWithoutHeader.left;
863fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee            bounds.right = mBoundsWithoutHeader.right;
864fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee        }
865d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
866d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
867d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected boolean isVisible(View view) {
868d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return view != null && view.getVisibility() == View.VISIBLE;
869d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
870d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
871d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
872d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Extracts width and height from the style
873d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
874d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private void ensurePhotoViewSize() {
875d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (!mPhotoViewWidthAndHeightAreReady) {
876d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoViewWidth = mPhotoViewHeight = getDefaultPhotoViewSize();
877d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (!mQuickContactEnabled && mPhotoView == null) {
878d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                if (!mKeepHorizontalPaddingForPhotoView) {
879d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    mPhotoViewWidth = 0;
880d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                }
881d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                if (!mKeepVerticalPaddingForPhotoView) {
882d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    mPhotoViewHeight = 0;
883d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                }
884d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
885d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
886d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoViewWidthAndHeightAreReady = true;
887d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
888d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
889d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
890d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected int getDefaultPhotoViewSize() {
891d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mDefaultPhotoViewSize;
892d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
893d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
894d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
895d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Gets a LayoutParam that corresponds to the default photo size.
896d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     *
897d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * @return A new LayoutParam.
898d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
899d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private LayoutParams getDefaultPhotoLayoutParams() {
900d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        LayoutParams params = generateDefaultLayoutParams();
901d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        params.width = getDefaultPhotoViewSize();
902d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        params.height = params.width;
903d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return params;
904d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
905d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
906d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
907d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected void drawableStateChanged() {
908d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        super.drawableStateChanged();
909d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mActivatedStateSupported) {
910d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mActivatedBackgroundDrawable.setState(getDrawableState());
911d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
912d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
913d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
914d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
915d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected boolean verifyDrawable(Drawable who) {
916d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return who == mActivatedBackgroundDrawable || super.verifyDrawable(who);
917d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
918d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
919d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
920d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void jumpDrawablesToCurrentState() {
921d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        super.jumpDrawablesToCurrentState();
922d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mActivatedStateSupported) {
923d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mActivatedBackgroundDrawable.jumpToCurrentState();
924d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
925d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
926d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
927d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
928d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void dispatchDraw(Canvas canvas) {
929d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mActivatedStateSupported && isActivated()) {
930d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mActivatedBackgroundDrawable.draw(canvas);
931d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
932d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
933d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        super.dispatchDraw(canvas);
934d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
935d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
936d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
937d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Sets section header or makes it invisible if the title is null.
938d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
939d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setSectionHeader(String title) {
940d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (!TextUtils.isEmpty(title)) {
941d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mHeaderTextView == null) {
942e9736747aa45ed6091a5479b38e3311823675853Yorke Lee                mHeaderTextView = new TextView(getContext());
943e9736747aa45ed6091a5479b38e3311823675853Yorke Lee                mHeaderTextView.setTextAppearance(getContext(), R.style.SectionHeaderStyle);
9446fdf16941587a222f554482fb72531783a924b6eAndrew Lee                mHeaderTextView.setGravity(
9456fdf16941587a222f554482fb72531783a924b6eAndrew Lee                        ViewUtil.isViewLayoutRtl(this) ? Gravity.RIGHT : Gravity.LEFT);
946d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                addView(mHeaderTextView);
947d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
948d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setMarqueeText(mHeaderTextView, title);
949d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mHeaderTextView.setVisibility(View.VISIBLE);
950d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mHeaderTextView.setAllCaps(true);
9511f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee        } else if (mHeaderTextView != null) {
9521f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee            mHeaderTextView.setVisibility(View.GONE);
953d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
954d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
955d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
9561f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee    public void setIsSectionHeaderEnabled(boolean isSectionHeaderEnabled) {
9571f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee        mIsSectionHeaderEnabled = isSectionHeaderEnabled;
9581f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee    }
9591f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee
960d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
961d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the quick contact badge, creating it if necessary.
962d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
963d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public QuickContactBadge getQuickContact() {
964d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (!mQuickContactEnabled) {
965d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            throw new IllegalStateException("QuickContact is disabled for this view");
966d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
967d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mQuickContact == null) {
968e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mQuickContact = new QuickContactBadge(getContext());
969e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang            if (CompatUtils.isLollipopCompatible()) {
970e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang                mQuickContact.setOverlay(null);
971e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang            }
972d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mQuickContact.setLayoutParams(getDefaultPhotoLayoutParams());
973d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mNameTextView != null) {
974e9736747aa45ed6091a5479b38e3311823675853Yorke Lee                mQuickContact.setContentDescription(getContext().getString(
975d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        R.string.description_quick_contact_for, mNameTextView.getText()));
976d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
977d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
978d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mQuickContact);
979d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoViewWidthAndHeightAreReady = false;
980d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
981d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mQuickContact;
982d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
983d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
984d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
985d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the photo view, creating it if necessary.
986d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
987d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public ImageView getPhotoView() {
988d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mPhotoView == null) {
989e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mPhotoView = new ImageView(getContext());
990d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoView.setLayoutParams(getDefaultPhotoLayoutParams());
991d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Quick contact style used above will set a background - remove it
992d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoView.setBackground(null);
993d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mPhotoView);
994d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoViewWidthAndHeightAreReady = false;
995d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
996d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mPhotoView;
997d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
998d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
999d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1000d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Removes the photo view.
1001d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1002d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void removePhotoView() {
1003d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        removePhotoView(false, true);
1004d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1005d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1006d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1007d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Removes the photo view.
1008d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     *
1009d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * @param keepHorizontalPadding True means data on the right side will have
1010d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     *            padding on left, pretending there is still a photo view.
1011d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * @param keepVerticalPadding True means the View will have some height
1012d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     *            enough for accommodating a photo view.
1013d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1014d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void removePhotoView(boolean keepHorizontalPadding, boolean keepVerticalPadding) {
1015d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mPhotoViewWidthAndHeightAreReady = false;
1016d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mKeepHorizontalPaddingForPhotoView = keepHorizontalPadding;
1017d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mKeepVerticalPaddingForPhotoView = keepVerticalPadding;
1018d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mPhotoView != null) {
1019d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            removeView(mPhotoView);
1020d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoView = null;
1021d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1022d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mQuickContact != null) {
1023d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            removeView(mQuickContact);
1024d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mQuickContact = null;
1025d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1026d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1027d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1028d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1029d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Sets a word prefix that will be highlighted if encountered in fields like
1030a81953a2b1818066ef5e44817f374ac288bab343Christine Chen     * name and search snippet. This will disable the mask highlighting for names.
1031d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * <p>
1032d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * NOTE: must be all upper-case
1033d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1034bd80fd64b9ff94c9ffbdb843beb4b363bb209463Chiao Cheng    public void setHighlightedPrefix(String upperCasePrefix) {
1035d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mHighlightedPrefix = upperCasePrefix;
1036a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    }
1037a81953a2b1818066ef5e44817f374ac288bab343Christine Chen
1038a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    /**
1039f99a990be713ed35afe64ba8133c5428816390c6Christine Chen     * Clears previously set highlight sequences for the view.
1040a81953a2b1818066ef5e44817f374ac288bab343Christine Chen     */
1041f99a990be713ed35afe64ba8133c5428816390c6Christine Chen    public void clearHighlightSequences() {
1042f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        mNameHighlightSequence.clear();
1043f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        mNumberHighlightSequence.clear();
1044a81953a2b1818066ef5e44817f374ac288bab343Christine Chen        mHighlightedPrefix = null;
1045a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    }
1046a81953a2b1818066ef5e44817f374ac288bab343Christine Chen
1047a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    /**
1048f99a990be713ed35afe64ba8133c5428816390c6Christine Chen     * Adds a highlight sequence to the name highlighter.
1049f99a990be713ed35afe64ba8133c5428816390c6Christine Chen     * @param start The start position of the highlight sequence.
1050f99a990be713ed35afe64ba8133c5428816390c6Christine Chen     * @param end The end position of the highlight sequence.
1051f99a990be713ed35afe64ba8133c5428816390c6Christine Chen     */
1052f99a990be713ed35afe64ba8133c5428816390c6Christine Chen    public void addNameHighlightSequence(int start, int end) {
1053f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        mNameHighlightSequence.add(new HighlightSequence(start, end));
1054f99a990be713ed35afe64ba8133c5428816390c6Christine Chen    }
1055f99a990be713ed35afe64ba8133c5428816390c6Christine Chen
1056f99a990be713ed35afe64ba8133c5428816390c6Christine Chen    /**
1057f99a990be713ed35afe64ba8133c5428816390c6Christine Chen     * Adds a highlight sequence to the number highlighter.
1058f99a990be713ed35afe64ba8133c5428816390c6Christine Chen     * @param start The start position of the highlight sequence.
1059f99a990be713ed35afe64ba8133c5428816390c6Christine Chen     * @param end The end position of the highlight sequence.
1060a81953a2b1818066ef5e44817f374ac288bab343Christine Chen     */
1061f99a990be713ed35afe64ba8133c5428816390c6Christine Chen    public void addNumberHighlightSequence(int start, int end) {
1062f99a990be713ed35afe64ba8133c5428816390c6Christine Chen        mNumberHighlightSequence.add(new HighlightSequence(start, end));
1063d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1064d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1065d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1066d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the text view for the contact name, creating it if necessary.
1067d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1068d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public TextView getNameTextView() {
1069d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mNameTextView == null) {
1070e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mNameTextView = new TextView(getContext());
1071d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView.setSingleLine(true);
1072d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView.setEllipsize(getTextEllipsis());
1073f88b7b9d1a07414053a4a90d13d453a02bd58ac7Nancy Chen            mNameTextView.setTextColor(mNameTextViewTextColor);
10743bc19a3bb1ed23b03352fff6de69a89e763a315eSai Cheemalapati            mNameTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
10753bc19a3bb1ed23b03352fff6de69a89e763a315eSai Cheemalapati                    mNameTextViewTextSize);
1076d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Manually call setActivated() since this view may be added after the first
1077d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // setActivated() call toward this whole item view.
1078d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView.setActivated(isActivated());
1079d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView.setGravity(Gravity.CENTER_VERTICAL);
10809f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            mNameTextView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
10819f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            mNameTextView.setId(R.id.cliv_name_textview);
1082e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang            if (CompatUtils.isLollipopCompatible()) {
1083e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang                mNameTextView.setElegantTextHeight(false);
1084e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang            }
1085d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mNameTextView);
1086d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1087d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mNameTextView;
1088d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1089d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1090d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1091d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Adds or updates a text view for the phonetic name.
1092d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1093d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setPhoneticName(char[] text, int size) {
1094d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (text == null || size == 0) {
1095d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mPhoneticNameTextView != null) {
1096d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mPhoneticNameTextView.setVisibility(View.GONE);
1097d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1098d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1099d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            getPhoneticNameTextView();
1100d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setMarqueeText(mPhoneticNameTextView, text, size);
1101d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.setVisibility(VISIBLE);
1102d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1103d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1104d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1105d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1106d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the text view for the phonetic name, creating it if necessary.
1107d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1108d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public TextView getPhoneticNameTextView() {
1109d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mPhoneticNameTextView == null) {
1110e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mPhoneticNameTextView = new TextView(getContext());
1111d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.setSingleLine(true);
1112d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.setEllipsize(getTextEllipsis());
1113e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mPhoneticNameTextView.setTextAppearance(getContext(), android.R.style.TextAppearance_Small);
11146f2673a25ecc59426c2faa2cfec5780e59ac5e5eWalter Jang            mPhoneticNameTextView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
1115d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.setTypeface(mPhoneticNameTextView.getTypeface(), Typeface.BOLD);
1116d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView.setActivated(isActivated());
11179f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            mPhoneticNameTextView.setId(R.id.cliv_phoneticname_textview);
1118d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mPhoneticNameTextView);
1119d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1120d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mPhoneticNameTextView;
1121d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1122d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1123d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1124d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Adds or updates a text view for the data label.
1125d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1126d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setLabel(CharSequence text) {
1127d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (TextUtils.isEmpty(text)) {
1128d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mLabelView != null) {
1129d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelView.setVisibility(View.GONE);
1130d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1131d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1132d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            getLabelView();
1133d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setMarqueeText(mLabelView, text);
1134d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mLabelView.setVisibility(VISIBLE);
1135d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1136d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1137d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1138d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1139d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the text view for the data label, creating it if necessary.
1140d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1141d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public TextView getLabelView() {
1142d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mLabelView == null) {
1143e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mLabelView = new TextView(getContext());
1144e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            mLabelView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
1145e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn                    LayoutParams.WRAP_CONTENT));
1146e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
1147d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mLabelView.setSingleLine(true);
1148d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mLabelView.setEllipsize(getTextEllipsis());
114990a368279bb3e94291e12fc0c7dc8676f194c33dYorke Lee            mLabelView.setTextAppearance(getContext(), R.style.TextAppearanceSmall);
1150d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mPhotoPosition == PhotoPosition.LEFT) {
1151d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelView.setAllCaps(true);
1152d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            } else {
1153d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mLabelView.setTypeface(mLabelView.getTypeface(), Typeface.BOLD);
1154d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1155d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mLabelView.setActivated(isActivated());
11569f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            mLabelView.setId(R.id.cliv_label_textview);
1157d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mLabelView);
1158d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1159d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mLabelView;
1160d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1161d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1162d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1163d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Adds or updates a text view for the data element.
1164d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1165a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    public void setData(char[] text, int size) {
1166d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (text == null || size == 0) {
1167d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mDataView != null) {
1168d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mDataView.setVisibility(View.GONE);
1169d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1170d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1171d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            getDataView();
1172d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setMarqueeText(mDataView, text, size);
1173d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataView.setVisibility(VISIBLE);
1174a81953a2b1818066ef5e44817f374ac288bab343Christine Chen        }
1175a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    }
1176a81953a2b1818066ef5e44817f374ac288bab343Christine Chen
1177a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    /**
1178a81953a2b1818066ef5e44817f374ac288bab343Christine Chen     * Sets phone number for a list item. This takes care of number highlighting if the highlight
1179a81953a2b1818066ef5e44817f374ac288bab343Christine Chen     * mask exists.
1180a81953a2b1818066ef5e44817f374ac288bab343Christine Chen     */
118162dbbf2f10e0e3bcb4d699d859a71a68c896f4a7Andrew Lee    public void setPhoneNumber(String text, String countryIso) {
1182a81953a2b1818066ef5e44817f374ac288bab343Christine Chen        if (text == null) {
1183a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            if (mDataView != null) {
1184a81953a2b1818066ef5e44817f374ac288bab343Christine Chen                mDataView.setVisibility(View.GONE);
11859f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            }
1186a81953a2b1818066ef5e44817f374ac288bab343Christine Chen        } else {
1187a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            getDataView();
118862dbbf2f10e0e3bcb4d699d859a71a68c896f4a7Andrew Lee
1189eabf27292960173c0600e022c64919453741c93fYorke Lee            // TODO: Format number using PhoneNumberUtils.formatNumber before assigning it to
1190eabf27292960173c0600e022c64919453741c93fYorke Lee            // mDataView. Make sure that determination of the highlight sequences are done only
1191eabf27292960173c0600e022c64919453741c93fYorke Lee            // after number formatting.
119262dbbf2f10e0e3bcb4d699d859a71a68c896f4a7Andrew Lee
1193a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            // Sets phone number texts for display after highlighting it, if applicable.
119462dbbf2f10e0e3bcb4d699d859a71a68c896f4a7Andrew Lee            // CharSequence textToSet = text;
1195f99a990be713ed35afe64ba8133c5428816390c6Christine Chen            final SpannableString textToSet = new SpannableString(text);
1196f99a990be713ed35afe64ba8133c5428816390c6Christine Chen
1197f99a990be713ed35afe64ba8133c5428816390c6Christine Chen            if (mNumberHighlightSequence.size() != 0) {
1198f99a990be713ed35afe64ba8133c5428816390c6Christine Chen                final HighlightSequence highlightSequence = mNumberHighlightSequence.get(0);
1199f99a990be713ed35afe64ba8133c5428816390c6Christine Chen                mTextHighlighter.applyMaskingHighlight(textToSet, highlightSequence.start,
1200f99a990be713ed35afe64ba8133c5428816390c6Christine Chen                        highlightSequence.end);
1201a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            }
1202f99a990be713ed35afe64ba8133c5428816390c6Christine Chen
1203a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            setMarqueeText(mDataView, textToSet);
1204a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            mDataView.setVisibility(VISIBLE);
1205a81953a2b1818066ef5e44817f374ac288bab343Christine Chen
1206a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            // We have a phone number as "mDataView" so make it always LTR and VIEW_START
1207a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            mDataView.setTextDirection(View.TEXT_DIRECTION_LTR);
1208a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            mDataView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
1209d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1210d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1211d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1212d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private void setMarqueeText(TextView textView, char[] text, int size) {
1213d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (getTextEllipsis() == TruncateAt.MARQUEE) {
1214d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setMarqueeText(textView, new String(text, 0, size));
1215d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1216d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textView.setText(text, 0, size);
1217d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1218d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1219d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1220d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private void setMarqueeText(TextView textView, CharSequence text) {
1221d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (getTextEllipsis() == TruncateAt.MARQUEE) {
1222d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // To show MARQUEE correctly (with END effect during non-active state), we need
1223d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // to build Spanned with MARQUEE in addition to TextView's ellipsize setting.
1224d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            final SpannableString spannable = new SpannableString(text);
1225d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            spannable.setSpan(TruncateAt.MARQUEE, 0, spannable.length(),
1226d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
1227d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textView.setText(spannable);
1228d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1229d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            textView.setText(text);
1230d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1231d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1232d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1233d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
12344ad6cc6d88af85a069a948a27b344465619b5ad8Wenyi Wang     * Returns the {@link CheckBox} view, creating it if necessary.
123508901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell     */
12364ad6cc6d88af85a069a948a27b344465619b5ad8Wenyi Wang    public CheckBox getCheckBox() {
123708901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        if (mCheckBox == null) {
12384ad6cc6d88af85a069a948a27b344465619b5ad8Wenyi Wang            mCheckBox = new CheckBox(getContext());
123908901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            // Make non-focusable, so the rest of the ContactListItemView can be clicked.
124008901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            mCheckBox.setFocusable(false);
124108901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            addView(mCheckBox);
124208901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        }
124308901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        return mCheckBox;
124408901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell    }
124508901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell
124608901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell    /**
1247d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the text view for the data text, creating it if necessary.
1248d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1249d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public TextView getDataView() {
1250d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mDataView == null) {
1251e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mDataView = new TextView(getContext());
1252d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataView.setSingleLine(true);
1253d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataView.setEllipsize(getTextEllipsis());
125490a368279bb3e94291e12fc0c7dc8676f194c33dYorke Lee            mDataView.setTextAppearance(getContext(), R.style.TextAppearanceSmall);
12556f2673a25ecc59426c2faa2cfec5780e59ac5e5eWalter Jang            mDataView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
1256d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mDataView.setActivated(isActivated());
12579f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            mDataView.setId(R.id.cliv_data_view);
1258e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang            if (CompatUtils.isLollipopCompatible()) {
1259e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang                mDataView.setElegantTextHeight(false);
1260e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang            }
1261d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mDataView);
1262d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1263d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mDataView;
1264d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1265d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1266d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1267d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Adds or updates a text view for the search snippet.
1268d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1269d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setSnippet(String text) {
1270d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (TextUtils.isEmpty(text)) {
1271d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mSnippetView != null) {
1272d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mSnippetView.setVisibility(View.GONE);
1273d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1274d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1275f99a990be713ed35afe64ba8133c5428816390c6Christine Chen            mTextHighlighter.setPrefixText(getSnippetView(), text, mHighlightedPrefix);
1276d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.setVisibility(VISIBLE);
1277d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang            if (ContactDisplayUtils.isPossiblePhoneNumber(text)) {
1278d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang                // Give the text-to-speech engine a hint that it's a phone number
12793abf10065b24373b3d6e46ed3c7f34af2b4639fbWenyi Wang                mSnippetView.setContentDescription(
12803abf10065b24373b3d6e46ed3c7f34af2b4639fbWenyi Wang                        PhoneNumberUtilsCompat.createTtsSpannable(text));
1281d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang            } else {
1282d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang                mSnippetView.setContentDescription(null);
1283d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang            }
1284d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1285d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1286d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1287d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1288d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the text view for the search snippet, creating it if necessary.
1289d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1290d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public TextView getSnippetView() {
1291d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mSnippetView == null) {
1292e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mSnippetView = new TextView(getContext());
1293d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.setSingleLine(true);
1294d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.setEllipsize(getTextEllipsis());
1295e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mSnippetView.setTextAppearance(getContext(), android.R.style.TextAppearance_Small);
12966f2673a25ecc59426c2faa2cfec5780e59ac5e5eWalter Jang            mSnippetView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
1297d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mSnippetView.setActivated(isActivated());
1298d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mSnippetView);
1299d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1300d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mSnippetView;
1301d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1302d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1303d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1304d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the text view for the status, creating it if necessary.
1305d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1306d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public TextView getStatusView() {
1307d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mStatusView == null) {
1308e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mStatusView = new TextView(getContext());
1309d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView.setSingleLine(true);
1310d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView.setEllipsize(getTextEllipsis());
1311e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mStatusView.setTextAppearance(getContext(), android.R.style.TextAppearance_Small);
1312d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView.setTextColor(mSecondaryTextColor);
1313d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView.setActivated(isActivated());
13149f0c1621718b382531cbebfe38907e6d3db6ceaeFabrice Di Meglio            mStatusView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
1315d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            addView(mStatusView);
1316d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1317d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mStatusView;
1318d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1319d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1320d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1321d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Adds or updates a text view for the status.
1322d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1323d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setStatus(CharSequence text) {
1324d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (TextUtils.isEmpty(text)) {
1325d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mStatusView != null) {
1326d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mStatusView.setVisibility(View.GONE);
1327d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1328d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1329d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            getStatusView();
1330d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setMarqueeText(mStatusView, text);
1331d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mStatusView.setVisibility(VISIBLE);
1332d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1333d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1334d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1335d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1336d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Adds or updates the presence icon view.
1337d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1338d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setPresence(Drawable icon) {
1339d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (icon != null) {
1340d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mPresenceIcon == null) {
1341e9736747aa45ed6091a5479b38e3311823675853Yorke Lee                mPresenceIcon = new ImageView(getContext());
1342d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                addView(mPresenceIcon);
1343d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1344d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPresenceIcon.setImageDrawable(icon);
1345d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPresenceIcon.setScaleType(ScaleType.CENTER);
1346d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPresenceIcon.setVisibility(View.VISIBLE);
1347d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1348d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (mPresenceIcon != null) {
1349d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                mPresenceIcon.setVisibility(View.GONE);
1350d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1351d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1352d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1353d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1354d19d35ef8347038f5296ed7020cab79396874937Victor Chang    /**
1355d19d35ef8347038f5296ed7020cab79396874937Victor Chang     * Set to display work profile icon or not
1356d19d35ef8347038f5296ed7020cab79396874937Victor Chang     *
1357d19d35ef8347038f5296ed7020cab79396874937Victor Chang     * @param enabled set to display work profile icon or not
1358d19d35ef8347038f5296ed7020cab79396874937Victor Chang     */
1359d19d35ef8347038f5296ed7020cab79396874937Victor Chang    public void setWorkProfileIconEnabled(boolean enabled) {
1360d19d35ef8347038f5296ed7020cab79396874937Victor Chang        if (mWorkProfileIcon != null) {
1361d19d35ef8347038f5296ed7020cab79396874937Victor Chang            mWorkProfileIcon.setVisibility(enabled ? View.VISIBLE : View.GONE);
1362d19d35ef8347038f5296ed7020cab79396874937Victor Chang        } else if (enabled) {
1363d19d35ef8347038f5296ed7020cab79396874937Victor Chang            mWorkProfileIcon = new ImageView(getContext());
1364d19d35ef8347038f5296ed7020cab79396874937Victor Chang            addView(mWorkProfileIcon);
1365d19d35ef8347038f5296ed7020cab79396874937Victor Chang            mWorkProfileIcon.setImageResource(R.drawable.ic_work_profile);
1366d19d35ef8347038f5296ed7020cab79396874937Victor Chang            mWorkProfileIcon.setScaleType(ScaleType.CENTER_INSIDE);
1367d19d35ef8347038f5296ed7020cab79396874937Victor Chang            mWorkProfileIcon.setVisibility(View.VISIBLE);
1368d19d35ef8347038f5296ed7020cab79396874937Victor Chang        }
1369d19d35ef8347038f5296ed7020cab79396874937Victor Chang    }
1370d19d35ef8347038f5296ed7020cab79396874937Victor Chang
1371d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private TruncateAt getTextEllipsis() {
1372d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return TruncateAt.MARQUEE;
1373d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1374d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1375d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void showDisplayName(Cursor cursor, int nameColumnIndex, int displayOrder) {
1376d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        CharSequence name = cursor.getString(nameColumnIndex);
137727330d80bb6575df2964112d34143125c8af9b78Yorke Lee        setDisplayName(name);
137827330d80bb6575df2964112d34143125c8af9b78Yorke Lee
137927330d80bb6575df2964112d34143125c8af9b78Yorke Lee        // Since the quick contact content description is derived from the display name and there is
138027330d80bb6575df2964112d34143125c8af9b78Yorke Lee        // no guarantee that when the quick contact is initialized the display name is already set,
138127330d80bb6575df2964112d34143125c8af9b78Yorke Lee        // do it here too.
138227330d80bb6575df2964112d34143125c8af9b78Yorke Lee        if (mQuickContact != null) {
1383e9736747aa45ed6091a5479b38e3311823675853Yorke Lee            mQuickContact.setContentDescription(getContext().getString(
138427330d80bb6575df2964112d34143125c8af9b78Yorke Lee                    R.string.description_quick_contact_for, mNameTextView.getText()));
138527330d80bb6575df2964112d34143125c8af9b78Yorke Lee        }
138627330d80bb6575df2964112d34143125c8af9b78Yorke Lee    }
138727330d80bb6575df2964112d34143125c8af9b78Yorke Lee
138827330d80bb6575df2964112d34143125c8af9b78Yorke Lee    public void setDisplayName(CharSequence name, boolean highlight) {
138927330d80bb6575df2964112d34143125c8af9b78Yorke Lee        if (!TextUtils.isEmpty(name) && highlight) {
139027330d80bb6575df2964112d34143125c8af9b78Yorke Lee            clearHighlightSequences();
139127330d80bb6575df2964112d34143125c8af9b78Yorke Lee            addNameHighlightSequence(0, name.length());
139227330d80bb6575df2964112d34143125c8af9b78Yorke Lee        }
139327330d80bb6575df2964112d34143125c8af9b78Yorke Lee        setDisplayName(name);
139427330d80bb6575df2964112d34143125c8af9b78Yorke Lee    }
139527330d80bb6575df2964112d34143125c8af9b78Yorke Lee
139627330d80bb6575df2964112d34143125c8af9b78Yorke Lee    public void setDisplayName(CharSequence name) {
1397d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (!TextUtils.isEmpty(name)) {
1398a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            // Chooses the available highlighting method for highlighting.
1399a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            if (mHighlightedPrefix != null) {
1400a81953a2b1818066ef5e44817f374ac288bab343Christine Chen                name = mTextHighlighter.applyPrefixHighlight(name, mHighlightedPrefix);
1401f99a990be713ed35afe64ba8133c5428816390c6Christine Chen            } else if (mNameHighlightSequence.size() != 0) {
1402f99a990be713ed35afe64ba8133c5428816390c6Christine Chen                final SpannableString spannableName = new SpannableString(name);
1403f99a990be713ed35afe64ba8133c5428816390c6Christine Chen                for (HighlightSequence highlightSequence : mNameHighlightSequence) {
1404f99a990be713ed35afe64ba8133c5428816390c6Christine Chen                    mTextHighlighter.applyMaskingHighlight(spannableName, highlightSequence.start,
1405f99a990be713ed35afe64ba8133c5428816390c6Christine Chen                            highlightSequence.end);
1406f99a990be713ed35afe64ba8133c5428816390c6Christine Chen                }
1407f99a990be713ed35afe64ba8133c5428816390c6Christine Chen                name = spannableName;
1408a81953a2b1818066ef5e44817f374ac288bab343Christine Chen            }
1409d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1410d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            name = mUnknownNameText;
1411d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1412d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        setMarqueeText(getNameTextView(), name);
1413d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang
1414d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang        if (ContactDisplayUtils.isPossiblePhoneNumber(name)) {
1415d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang            // Give the text-to-speech engine a hint that it's a phone number
14167b03f132552cbee9b5df1958621bcf808217c2c6Tingting Wang            mNameTextView.setTextDirection(View.TEXT_DIRECTION_LTR);
1417d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang            mNameTextView.setContentDescription(
14183abf10065b24373b3d6e46ed3c7f34af2b4639fbWenyi Wang                    PhoneNumberUtilsCompat.createTtsSpannable(name.toString()));
1419d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang        } else {
142082f67c1535b00320bdcc7df603c0f259df7b83a4Qi Wang            // Remove span tags of highlighting for talkback to avoid reading highlighting and rest
142182f67c1535b00320bdcc7df603c0f259df7b83a4Qi Wang            // of the name into two separate parts.
142282f67c1535b00320bdcc7df603c0f259df7b83a4Qi Wang            mNameTextView.setContentDescription(name.toString());
1423d4c540b696b2575f32b3bb9f7f34248ea18c37b4Walter Jang        }
1424d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1425d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
142608901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell    public void hideCheckBox() {
142708901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        if (mCheckBox != null) {
142808901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            removeView(mCheckBox);
142908901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell            mCheckBox = null;
143008901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell        }
143108901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell    }
143208901312c70a244e5785668cdbe1a009ed9b67a8Brian Attwell
1433d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void hideDisplayName() {
1434d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mNameTextView != null) {
1435d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            removeView(mNameTextView);
1436d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mNameTextView = null;
1437d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1438d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1439d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1440d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void showPhoneticName(Cursor cursor, int phoneticNameColumnIndex) {
1441d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        cursor.copyStringToBuffer(phoneticNameColumnIndex, mPhoneticNameBuffer);
1442d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int phoneticNameSize = mPhoneticNameBuffer.sizeCopied;
1443d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (phoneticNameSize != 0) {
1444d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setPhoneticName(mPhoneticNameBuffer.data, phoneticNameSize);
1445d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
1446d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setPhoneticName(null, 0);
1447d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1448d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1449d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1450d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void hidePhoneticName() {
1451d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mPhoneticNameTextView != null) {
1452d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            removeView(mPhoneticNameTextView);
1453d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhoneticNameTextView = null;
1454d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1455d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1456d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1457d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1458d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Sets the proper icon (star or presence or nothing) and/or status message.
1459d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1460d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void showPresenceAndStatusMessage(Cursor cursor, int presenceColumnIndex,
1461d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            int contactStatusColumnIndex) {
1462d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        Drawable icon = null;
1463d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int presence = 0;
1464d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (!cursor.isNull(presenceColumnIndex)) {
1465d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            presence = cursor.getInt(presenceColumnIndex);
1466d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            icon = ContactPresenceIconUtil.getPresenceIcon(getContext(), presence);
1467d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1468d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        setPresence(icon);
1469d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1470d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        String statusMessage = null;
1471d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (contactStatusColumnIndex != 0 && !cursor.isNull(contactStatusColumnIndex)) {
1472d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            statusMessage = cursor.getString(contactStatusColumnIndex);
1473d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1474d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // If there is no status message from the contact, but there was a presence value, then use
1475d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // the default status message string
1476d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (statusMessage == null && presence != 0) {
1477d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            statusMessage = ContactStatusUtil.getStatusString(getContext(), presence);
1478d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1479d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        setStatus(statusMessage);
1480d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1481d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1482d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1483938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang     * Shows search snippet for email and phone number matches.
1484938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang     */
1485938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang    public void showSnippet(Cursor cursor, String query, int snippetColumn) {
1486938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang        // TODO: this does not properly handle phone numbers with control characters
1487938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang        // For example if the phone number is 444-5555, the search query 4445 will match the
1488938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang        // number since we normalize it before querying CP2 but the snippet will fail since
1489938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang        // the portion to be highlighted is 444-5 not 4445.
1490938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang        final String snippet = cursor.getString(snippetColumn);
1491938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang        if (snippet == null) {
1492938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang            setSnippet(null);
1493938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang            return;
1494938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang        }
1495938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang        final String displayName = cursor.getColumnIndex(Contacts.DISPLAY_NAME) >= 0
1496938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang                ? cursor.getString(cursor.getColumnIndex(Contacts.DISPLAY_NAME)) : null;
1497938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang        if (snippet.equals(displayName)) {
1498938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang            // If the snippet exactly matches the display name (i.e. the phone number or email
1499938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang            // address is being used as the display name) then no snippet is necessary
1500938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang            setSnippet(null);
1501938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang            return;
1502938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang        }
1503938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang        // Show the snippet with the part of the query that matched it
1504938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang        setSnippet(updateSnippet(snippet, query, displayName));
1505938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang    }
1506938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang
1507938440c2a5da9ae8b6c88a21210fd0f624ffb3f1Walter Jang    /**
1508d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Shows search snippet.
1509d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1510d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void showSnippet(Cursor cursor, int summarySnippetColumnIndex) {
151173f41231df9868953047cbbcce529ee5687de7f2Walter Jang        if (cursor.getColumnCount() <= summarySnippetColumnIndex
151273f41231df9868953047cbbcce529ee5687de7f2Walter Jang            || !SearchSnippets.SNIPPET.equals(cursor.getColumnName(summarySnippetColumnIndex))) {
1513d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setSnippet(null);
1514d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            return;
1515d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1516d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
151705897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        String snippet = cursor.getString(summarySnippetColumnIndex);
1518cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1519d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Do client side snippeting if provider didn't do it
152005897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        final Bundle extras = cursor.getExtras();
1521d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (extras.getBoolean(ContactsContract.DEFERRED_SNIPPETING)) {
1522d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
152305897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng            final String query = extras.getString(ContactsContract.DEFERRED_SNIPPETING_QUERY);
1524cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1525cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            String displayName = null;
1526cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            int displayNameIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
1527cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            if (displayNameIndex >= 0) {
1528cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                displayName = cursor.getString(displayNameIndex);
152905897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng            }
1530cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1531cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            snippet = updateSnippet(snippet, query, displayName);
1532cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
153305897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        } else {
153405897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng            if (snippet != null) {
153505897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                int from = 0;
153605897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                int to = snippet.length();
153705897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                int start = snippet.indexOf(DefaultContactListAdapter.SNIPPET_START_MATCH);
153805897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                if (start == -1) {
153905897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    snippet = null;
154005897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                } else {
154105897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    int firstNl = snippet.lastIndexOf('\n', start);
154205897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    if (firstNl != -1) {
154305897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        from = firstNl + 1;
154405897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    }
154505897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    int end = snippet.lastIndexOf(DefaultContactListAdapter.SNIPPET_END_MATCH);
154605897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    if (end != -1) {
154705897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        int lastNl = snippet.indexOf('\n', end);
154805897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        if (lastNl != -1) {
154905897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                            to = lastNl;
155005897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        }
155105897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    }
1552d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
155305897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    StringBuilder sb = new StringBuilder();
155405897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    for (int i = from; i < to; i++) {
155505897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        char c = snippet.charAt(i);
155605897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        if (c != DefaultContactListAdapter.SNIPPET_START_MATCH &&
155705897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                                c != DefaultContactListAdapter.SNIPPET_END_MATCH) {
155805897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                            sb.append(c);
155905897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                        }
1560d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    }
156105897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng                    snippet = sb.toString();
1562d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                }
1563d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
1564d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
1565cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1566d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        setSnippet(snippet);
1567d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1568d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1569cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng    /**
1570cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     * Used for deferred snippets from the database. The contents come back as large strings which
1571cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     * need to be extracted for display.
1572cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     *
1573cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     * @param snippet The snippet from the database.
1574cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     * @param query The search query substring.
1575cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     * @param displayName The contact display name.
1576cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     * @return The proper snippet to display.
1577cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng     */
1578cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng    private String updateSnippet(String snippet, String query, String displayName) {
1579cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1580cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        if (TextUtils.isEmpty(snippet) || TextUtils.isEmpty(query)) {
1581cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            return null;
1582cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1583cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        query = SearchUtil.cleanStartAndEndOfSearchQuery(query.toLowerCase());
1584cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1585cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // If the display name already contains the query term, return empty - snippets should
1586cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // not be needed in that case.
1587cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        if (!TextUtils.isEmpty(displayName)) {
1588cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            final String lowerDisplayName = displayName.toLowerCase();
1589cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            final List<String> nameTokens = split(lowerDisplayName);
1590cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            for (String nameToken : nameTokens) {
1591cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                if (nameToken.startsWith(query)) {
1592cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                    return null;
1593cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                }
1594cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            }
1595cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1596cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1597cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // The snippet may contain multiple data lines.
1598cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Show the first line that matches the query.
1599cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        final SearchUtil.MatchedLine matched = SearchUtil.findMatchingLine(snippet, query);
1600cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1601cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        if (matched != null && matched.line != null) {
1602cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            // Tokenize for long strings since the match may be at the end of it.
1603cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            // Skip this part for short strings since the whole string will be displayed.
1604cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            // Most contact strings are short so the snippetize method will be called infrequently.
1605cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            final int lengthThreshold = getResources().getInteger(
1606cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                    R.integer.snippet_length_before_tokenize);
1607cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            if (matched.line.length() > lengthThreshold) {
1608cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                return snippetize(matched.line, matched.startIndex, lengthThreshold);
1609cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            } else {
1610cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                return matched.line;
1611cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            }
1612cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1613cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1614cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // No match found.
1615cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        return null;
1616cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng    }
1617cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1618cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng    private String snippetize(String line, int matchIndex, int maxLength) {
1619cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Show up to maxLength characters. But we only show full tokens so show the last full token
1620cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // up to maxLength characters. So as many starting tokens as possible before trying ending
1621cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // tokens.
1622cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        int remainingLength = maxLength;
1623cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        int tempRemainingLength = remainingLength;
1624cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1625cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Start the end token after the matched query.
1626cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        int index = matchIndex;
1627cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        int endTokenIndex = index;
1628cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1629cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Find the match token first.
1630cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        while (index < line.length()) {
1631cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            if (!Character.isLetterOrDigit(line.charAt(index))) {
1632cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                endTokenIndex = index;
1633cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                remainingLength = tempRemainingLength;
1634cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                break;
1635cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            }
1636cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            tempRemainingLength--;
1637cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            index++;
1638cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1639cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1640cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Find as much content before the match.
1641cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        index = matchIndex - 1;
1642cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        tempRemainingLength = remainingLength;
1643cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        int startTokenIndex = matchIndex;
1644cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        while (index > -1 && tempRemainingLength > 0) {
1645cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            if (!Character.isLetterOrDigit(line.charAt(index))) {
1646cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                startTokenIndex = index;
1647cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                remainingLength = tempRemainingLength;
1648cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            }
1649cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            tempRemainingLength--;
1650cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            index--;
1651cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1652cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
1653cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        index = endTokenIndex;
1654cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        tempRemainingLength = remainingLength;
1655cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Find remaining content at after match.
1656cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        while (index < line.length() && tempRemainingLength > 0) {
1657cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            if (!Character.isLetterOrDigit(line.charAt(index))) {
1658cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                endTokenIndex = index;
1659cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            }
1660cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            tempRemainingLength--;
1661cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            index++;
1662cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1663cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        // Append ellipse if there is content before or after.
1664cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        final StringBuilder sb = new StringBuilder();
1665cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        if (startTokenIndex > 0) {
1666cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            sb.append("...");
1667cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1668cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        sb.append(line.substring(startTokenIndex, endTokenIndex));
1669cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        if (endTokenIndex < line.length()) {
1670cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            sb.append("...");
1671cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        }
1672cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng        return sb.toString();
1673cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng    }
1674cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng
167505897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng    private static final Pattern SPLIT_PATTERN = Pattern.compile(
167605897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng            "([\\w-\\.]+)@((?:[\\w]+\\.)+)([a-zA-Z]{2,4})|[\\w]+");
167705897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng
167805897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng    /**
167905897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     * Helper method for splitting a string into tokens.  The lists passed in are populated with
168005897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     * the
168105897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     * tokens and offsets into the content of each token.  The tokenization function parses e-mail
168205897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     * addresses as a single token; otherwise it splits on any non-alphanumeric character.
168305897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     *
168405897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     * @param content Content to split.
168505897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     * @return List of token strings.
168605897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng     */
168705897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng    private static List<String> split(String content) {
168805897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        final Matcher matcher = SPLIT_PATTERN.matcher(content);
168905897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        final ArrayList<String> tokens = Lists.newArrayList();
169005897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        while (matcher.find()) {
169105897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng            tokens.add(matcher.group());
169205897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        }
169305897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng        return tokens;
169405897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng    }
169505897c8e016942e10f0ef6f0da02d339480d4748Chiao Cheng
1696d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
16977a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner     * Shows data element.
1698d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
1699d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void showData(Cursor cursor, int dataColumnIndex) {
1700d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        cursor.copyStringToBuffer(dataColumnIndex, mDataBuffer);
17017a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        setData(mDataBuffer.data, mDataBuffer.sizeCopied);
17027a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner    }
17037a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner
1704d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setActivatedStateSupported(boolean flag) {
1705d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        this.mActivatedStateSupported = flag;
1706d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1707d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1708fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee    public void setAdjustSelectionBoundsEnabled(boolean enabled) {
1709fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee        mAdjustSelectionBoundsEnabled = enabled;
1710fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee    }
1711fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee
1712d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
1713d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void requestLayout() {
1714d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // We will assume that once measured this will not need to resize
1715d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // itself, so there is no need to pass the layout request to the parent
1716d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // view (ListView).
1717d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        forceLayout();
1718d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1719d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1720d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setPhotoPosition(PhotoPosition photoPosition) {
1721d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mPhotoPosition = photoPosition;
1722d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1723d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1724d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public PhotoPosition getPhotoPosition() {
1725d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mPhotoPosition;
1726d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
1727d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
1728d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
1729e05a0f5d375168585594fccf68a3ec60a88d4430Andrew Lee     * Set drawable resources directly for the drawable resource of the photo view.
173027330d80bb6575df2964112d34143125c8af9b78Yorke Lee     *
1731e05a0f5d375168585594fccf68a3ec60a88d4430Andrew Lee     * @param drawableId Id of drawable resource.
173227330d80bb6575df2964112d34143125c8af9b78Yorke Lee     */
1733e05a0f5d375168585594fccf68a3ec60a88d4430Andrew Lee    public void setDrawableResource(int drawableId) {
1734e05a0f5d375168585594fccf68a3ec60a88d4430Andrew Lee        ImageView photo = getPhotoView();
173527330d80bb6575df2964112d34143125c8af9b78Yorke Lee        photo.setScaleType(ImageView.ScaleType.CENTER);
1736e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang        final Drawable drawable = ContextCompat.getDrawable(getContext(), drawableId);
1737e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang        final int iconColor =
1738e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang                ContextCompat.getColor(getContext(), R.color.search_shortcut_icon_color);
1739e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang        if (CompatUtils.isLollipopCompatible()) {
1740e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang            photo.setImageDrawable(drawable);
1741e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang            photo.setImageTintList(ColorStateList.valueOf(iconColor));
1742e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang        } else {
1743e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang            final Drawable drawableWrapper = DrawableCompat.wrap(drawable).mutate();
1744e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang            DrawableCompat.setTint(drawableWrapper, iconColor);
1745e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang            photo.setImageDrawable(drawableWrapper);
1746e0bb103a1403d3657cafb27cda6dc6b5fb1d5462Wenyi Wang        }
174727330d80bb6575df2964112d34143125c8af9b78Yorke Lee    }
174810349f190691f802b8935175dbf38bff74a8a703Yorke Lee
174910349f190691f802b8935175dbf38bff74a8a703Yorke Lee    @Override
175010349f190691f802b8935175dbf38bff74a8a703Yorke Lee    public boolean onTouchEvent(MotionEvent event) {
175110349f190691f802b8935175dbf38bff74a8a703Yorke Lee        final float x = event.getX();
175210349f190691f802b8935175dbf38bff74a8a703Yorke Lee        final float y = event.getY();
1753538e05b3bbde399f25ccf1aad251fca6d7f4d6b3Yorke Lee        // If the touch event's coordinates are not within the view's header, then delegate
1754538e05b3bbde399f25ccf1aad251fca6d7f4d6b3Yorke Lee        // to super.onTouchEvent so that regular view behavior is preserved. Otherwise, consume
1755538e05b3bbde399f25ccf1aad251fca6d7f4d6b3Yorke Lee        // and ignore the touch event.
1756bded9d078784569efef4aec2d636ce3f733601d7Yorke Lee        if (mBoundsWithoutHeader.contains((int) x, (int) y) || !pointIsInView(x, y)) {
175710349f190691f802b8935175dbf38bff74a8a703Yorke Lee            return super.onTouchEvent(event);
175810349f190691f802b8935175dbf38bff74a8a703Yorke Lee        } else {
175910349f190691f802b8935175dbf38bff74a8a703Yorke Lee            return true;
176010349f190691f802b8935175dbf38bff74a8a703Yorke Lee        }
176110349f190691f802b8935175dbf38bff74a8a703Yorke Lee    }
1762bded9d078784569efef4aec2d636ce3f733601d7Yorke Lee
1763bded9d078784569efef4aec2d636ce3f733601d7Yorke Lee    private final boolean pointIsInView(float localX, float localY) {
1764f7a205fdcb17161c454bee673cc2fce5b23d0760Sai Cheemalapati        return localX >= mLeftOffset && localX < mRightOffset
17653d7e2893cb55dc0f1bc4f7e731322973ee09bc1fYorke Lee                && localY >= 0 && localY < (getBottom() - getTop());
1766bded9d078784569efef4aec2d636ce3f733601d7Yorke Lee    }
1767d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng}
1768