CallLogAdapter.java revision e80d62229bb11a92f0db8d4e4bac6533bbed9b66
194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng/*
294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * Copyright (C) 2011 The Android Open Source Project
394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng *
494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * Licensed under the Apache License, Version 2.0 (the "License");
594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * you may not use this file except in compliance with the License.
694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * You may obtain a copy of the License at
794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng *
894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng *      http://www.apache.org/licenses/LICENSE-2.0
994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng *
1094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * Unless required by applicable law or agreed to in writing, software
1194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * distributed under the License is distributed on an "AS IS" BASIS,
1294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * See the License for the specific language governing permissions and
1494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * limitations under the License.
1594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng */
1694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
1794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengpackage com.android.dialer.calllog;
1894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
1994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.content.ContentValues;
2094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.content.Context;
21c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Chengimport android.content.Intent;
2294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.content.res.Resources;
2394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.database.Cursor;
2487ba489564b25d4a64c9faaeafea46e2f72d8933Nancy Chenimport android.graphics.drawable.Drawable;
2594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.net.Uri;
2694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.os.Handler;
2794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.os.Message;
2894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.provider.CallLog.Calls;
2994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.provider.ContactsContract.PhoneLookup;
309dc924c8bcc0bc8d996452e9ce3215b5f064962eTyler Gunnimport android.telecom.PhoneAccountHandle;
3194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.text.TextUtils;
3294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.view.LayoutInflater;
3394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.view.View;
34b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Leeimport android.view.View.AccessibilityDelegate;
3594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.view.ViewGroup;
36c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Chengimport android.view.ViewStub;
3794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.view.ViewTreeObserver;
38b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Leeimport android.view.accessibility.AccessibilityEvent;
39c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Chengimport android.widget.ImageView;
40c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Chengimport android.widget.TextView;
41b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapatiimport android.widget.Toast;
4294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
4394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport com.android.common.widget.GroupingListAdapter;
44ac7f2354a58bac2099b6a9442f6c8388fcf1c148Tyler Gunnimport com.android.contacts.common.CallUtil;
4535071c06d1587942f5a66c8f12e6247e8f904d26Chiao Chengimport com.android.contacts.common.ContactPhotoManager;
4656cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Leeimport com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
4735071c06d1587942f5a66c8f12e6247e8f904d26Chiao Chengimport com.android.contacts.common.util.UriUtils;
48eb141e078353a2e3a997001afd1aa16a88da429bAndrew Leeimport com.android.dialer.DialtactsActivity;
4994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport com.android.dialer.PhoneCallDetails;
5094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport com.android.dialer.PhoneCallDetailsHelper;
519554500572ba82fbd7adb0a1637206ef870ef09eChiao Chengimport com.android.dialer.R;
527d20f8273886411ffc864231d59f780e450de3dbYorke Leeimport com.android.dialer.util.DialerUtils;
5394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport com.android.dialer.util.ExpirableCache;
5456cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee
5594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport com.google.common.annotations.VisibleForTesting;
5694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport com.google.common.base.Objects;
5794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
58146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunnimport java.util.HashMap;
5994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport java.util.LinkedList;
6094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
6194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng/**
6294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * Adapter class to fill in data for the Call Log.
6394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng */
64fb585079cc4c522c27f6dd6bf03fd296535960f3Yorke Leepublic class CallLogAdapter extends GroupingListAdapter
6594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        implements ViewTreeObserver.OnPreDrawListener, CallLogGroupBuilder.GroupCreator {
66c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
67f42ea913f3569e0bef2ae18404b29610f368cc77Yorke Lee    private static final int VOICEMAIL_TRANSCRIPTION_MAX_LINES = 10;
68f42ea913f3569e0bef2ae18404b29610f368cc77Yorke Lee
69146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /** The enumeration of {@link android.os.AsyncTask} objects used in this class. */
70146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    public enum Tasks {
71146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        REMOVE_CALL_LOG_ENTRIES,
72146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    }
73146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
74654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee    /** Interface used to inform a parent UI element that a list item has been expanded. */
75654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee    public interface CallItemExpandedListener {
76654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee        /**
77654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee         * @param view The {@link CallLogListItemView} that represents the item that was clicked
78654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee         *         on.
79654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee         */
80654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee        public void onItemExpanded(CallLogListItemView view);
818ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn
828ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn        /**
8368e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn         * Retrieves the call log view for the specified call Id.  If the view is not currently
8468e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn         * visible, returns null.
858ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn         *
8668e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn         * @param callId The call Id.
8768e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn         * @return The call log view.
888ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn         */
8968e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn        public CallLogListItemView getViewForCallId(long callId);
90654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee    }
91654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee
9294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Interface used to initiate a refresh of the content. */
9394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    public interface CallFetcher {
9494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public void fetchCalls();
9594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
9694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
979686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati    /** Implements onClickListener for the report button. */
989686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati    public interface OnReportButtonClickListener {
999686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati        public void onReportButtonClick(String number);
1009686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati    }
1019686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati
10294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
10394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Stores a phone number of a call with the country code where it originally occurred.
10494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
10594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Note the country does not necessarily specifies the country of the phone number itself, but
10694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * it is the country in which the user was in when the call was placed or received.
10794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
10894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private static final class NumberWithCountryIso {
10994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public final String number;
11094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public final String countryIso;
11194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
11294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public NumberWithCountryIso(String number, String countryIso) {
11394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            this.number = number;
11494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            this.countryIso = countryIso;
11594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
11694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
11794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        @Override
11894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public boolean equals(Object o) {
11994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (o == null) return false;
12094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!(o instanceof NumberWithCountryIso)) return false;
12194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            NumberWithCountryIso other = (NumberWithCountryIso) o;
12294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            return TextUtils.equals(number, other.number)
12394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    && TextUtils.equals(countryIso, other.countryIso);
12494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
12594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
12694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        @Override
12794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public int hashCode() {
12894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            return (number == null ? 0 : number.hashCode())
12994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    ^ (countryIso == null ? 0 : countryIso.hashCode());
13094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
13194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
13294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
13394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** The time in millis to delay starting the thread processing requests. */
13494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private static final int START_PROCESSING_REQUESTS_DELAY_MILLIS = 1000;
13594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
13694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** The size of the cache of contact info. */
13794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private static final int CONTACT_INFO_CACHE_SIZE = 100;
13894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
1398ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn    /** Constant used to indicate no row is expanded. */
1408ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn    private static final long NONE_EXPANDED = -1;
1418ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn
142704acc087ce359295475a46695c2821c55778344Chiao Cheng    protected final Context mContext;
14394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private final ContactInfoHelper mContactInfoHelper;
14494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private final CallFetcher mCallFetcher;
145b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati    private final Toast mReportedToast;
1469686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati    private final OnReportButtonClickListener mOnReportButtonClickListener;
14794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private ViewTreeObserver mViewTreeObserver = null;
14894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
14994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
15094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * A cache of the contact details for the phone numbers in the call log.
15194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
15294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * The content of the cache is expired (but not purged) whenever the application comes to
15394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * the foreground.
15494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
15594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * The key is number with the country in which the call was placed or received.
15694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
15794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private ExpirableCache<NumberWithCountryIso, ContactInfo> mContactInfoCache;
15894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
1598ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn    /**
1608ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     * Tracks the call log row which was previously expanded.  Used so that the closure of a
1618ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     * previously expanded call log entry can be animated on rebind.
1628ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     */
1638ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn    private long mPreviouslyExpanded = NONE_EXPANDED;
1648ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn
1658ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn    /**
1668ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     * Tracks the currently expanded call log row.
1678ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     */
1688ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn    private long mCurrentlyExpanded = NONE_EXPANDED;
169146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
17094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
1714dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  Hashmap, keyed by call Id, used to track the day group for a call.  As call log entries are
1724dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  put into the primary call groups in {@link com.android.dialer.calllog.CallLogGroupBuilder},
1734dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  they are also assigned a secondary "day group".  This hashmap tracks the day group assigned
1744dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  to all calls in the call log.  This information is used to trigger the display of a day
1754dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  group header above the call log entry at the start of a day group.
1764dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  Note: Multiple calls are grouped into a single primary "call group" in the call log, and
1774dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  the cursor used to bind rows includes all of these calls.  When determining if a day group
1784dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  change has occurred it is necessary to look at the last entry in the call log to determine
1794dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  its day group.  This hashmap provides a means of determining the previous day group without
1804dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  having to reverse the cursor to the start of the previous day call log entry.
1814dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     */
1824dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    private HashMap<Long,Integer> mDayGroups = new HashMap<Long, Integer>();
1834dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn
1844dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    /**
18594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * A request for contact details for the given number.
18694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
18794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private static final class ContactInfoRequest {
18894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        /** The number to look-up. */
18994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public final String number;
19094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        /** The country in which a call to or from this number was placed or received. */
19194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public final String countryIso;
19294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        /** The cached contact information stored in the call log. */
19394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public final ContactInfo callLogInfo;
19494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
19594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public ContactInfoRequest(String number, String countryIso, ContactInfo callLogInfo) {
19694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            this.number = number;
19794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            this.countryIso = countryIso;
19894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            this.callLogInfo = callLogInfo;
19994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
20094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
20194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        @Override
20294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public boolean equals(Object obj) {
20394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (this == obj) return true;
20494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (obj == null) return false;
20594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!(obj instanceof ContactInfoRequest)) return false;
20694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
20794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            ContactInfoRequest other = (ContactInfoRequest) obj;
20894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
20994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!TextUtils.equals(number, other.number)) return false;
21094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!TextUtils.equals(countryIso, other.countryIso)) return false;
21194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!Objects.equal(callLogInfo, other.callLogInfo)) return false;
21294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
21394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            return true;
21494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
21594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
21694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        @Override
21794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public int hashCode() {
21894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            final int prime = 31;
21994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            int result = 1;
22094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            result = prime * result + ((callLogInfo == null) ? 0 : callLogInfo.hashCode());
22194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            result = prime * result + ((countryIso == null) ? 0 : countryIso.hashCode());
22294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            result = prime * result + ((number == null) ? 0 : number.hashCode());
22394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            return result;
22494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
22594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
22694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
22794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
22894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * List of requests to update contact details.
22994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
23094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Each request is made of a phone number to look up, and the contact info currently stored in
23194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * the call log for this number.
23294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
23394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * The requests are added when displaying the contacts and are processed by a background
23494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * thread.
23594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
23694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private final LinkedList<ContactInfoRequest> mRequests;
23794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
23894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private boolean mLoading = true;
23994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private static final int REDRAW = 1;
24094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private static final int START_THREAD = 2;
24194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
24294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private QueryThread mCallerIdThread;
24394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
24494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Instance of helper class for managing views. */
24594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private final CallLogListItemHelper mCallLogViewsHelper;
24694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
24794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Helper to set up contact photos. */
24894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private final ContactPhotoManager mContactPhotoManager;
24994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Helper to parse and process phone numbers. */
25024ec319f8d410be8a1923c4033f927165876cbabYorke Lee    private PhoneNumberDisplayHelper mPhoneNumberHelper;
251e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen    /** Helper to access Telephony phone number utils class */
252e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen    protected final PhoneNumberUtilsWrapper mPhoneNumberUtilsWrapper;
25394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Helper to group call log entries. */
25494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private final CallLogGroupBuilder mCallLogGroupBuilder;
25594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
256654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee    private CallItemExpandedListener mCallItemExpandedListener;
257654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee
25894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Can be set to true by tests to disable processing of requests. */
25994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private volatile boolean mRequestProcessingDisabled = false;
26094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
261c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    private boolean mIsCallLog = true;
262c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
263c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    private View mBadgeContainer;
264c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    private ImageView mBadgeImageView;
265c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    private TextView mBadgeText;
266c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
267b2687dd09eef2fc1aaf31ea4a3edf523677108a8Andrew Lee    private int mCallLogBackgroundColor;
268b2687dd09eef2fc1aaf31ea4a3edf523677108a8Andrew Lee    private int mExpandedBackgroundColor;
269b2687dd09eef2fc1aaf31ea4a3edf523677108a8Andrew Lee    private float mExpandedTranslationZ;
270b2687dd09eef2fc1aaf31ea4a3edf523677108a8Andrew Lee
271643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng    /** Listener for the primary or secondary actions in the list.
272643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng     *  Primary opens the call details.
273643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng     *  Secondary calls or plays.
274643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng     **/
275643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng    private final View.OnClickListener mActionListener = new View.OnClickListener() {
27694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        @Override
27794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public void onClick(View view) {
278643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng            startActivityForAction(view);
27994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
28094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    };
281643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng
282146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /**
283146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * The onClickListener used to expand or collapse the action buttons section for a call log
284146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * entry.
285146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     */
286146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    private final View.OnClickListener mExpandCollapseListener = new View.OnClickListener() {
287146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        @Override
288146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        public void onClick(View v) {
289654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee            final CallLogListItemView callLogItem = (CallLogListItemView) v.getParent().getParent();
290b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee            handleRowExpanded(callLogItem, true /* animate */, false /* forceExpand */);
291b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee        }
292b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee    };
29368e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn
294b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee    private AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() {
295b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee        @Override
296b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee        public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
297b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee                AccessibilityEvent event) {
298b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee            if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) {
299b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee                handleRowExpanded((CallLogListItemView) host, false /* animate */,
300b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee                        true /* forceExpand */);
30168e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn            }
302b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee            return super.onRequestSendAccessibilityEvent(host, child, event);
303146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
304146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    };
305146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
306643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng    private void startActivityForAction(View view) {
307643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng        final IntentProvider intentProvider = (IntentProvider) view.getTag();
308643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng        if (intentProvider != null) {
309643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng            final Intent intent = intentProvider.getIntent(mContext);
310643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng            // See IntentProvider.getCallDetailIntentProvider() for why this may be null.
311643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng            if (intent != null) {
3127d20f8273886411ffc864231d59f780e450de3dbYorke Lee                DialerUtils.startActivityWithErrorToast(mContext, intent);
31394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
31494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
315643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng    }
31694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
31794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
31894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    public boolean onPreDraw() {
31994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // We only wanted to listen for the first draw (and this is it).
32094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        unregisterPreDrawListener();
32194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
32294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Only schedule a thread-creation message if the thread hasn't been
32394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // created yet. This is purely an optimization, to queue fewer messages.
32494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (mCallerIdThread == null) {
32594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mHandler.sendEmptyMessageDelayed(START_THREAD, START_PROCESSING_REQUESTS_DELAY_MILLIS);
32694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
32794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
32894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        return true;
32994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
33094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
33194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private Handler mHandler = new Handler() {
33294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        @Override
33394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public void handleMessage(Message msg) {
33494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            switch (msg.what) {
33594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                case REDRAW:
33694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    notifyDataSetChanged();
33794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    break;
33894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                case START_THREAD:
33994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    startRequestProcessing();
34094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    break;
34194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
34294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
34394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    };
34494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
345fb585079cc4c522c27f6dd6bf03fd296535960f3Yorke Lee    public CallLogAdapter(Context context, CallFetcher callFetcher,
346654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee            ContactInfoHelper contactInfoHelper, CallItemExpandedListener callItemExpandedListener,
3479686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati            OnReportButtonClickListener onReportButtonClickListener, boolean isCallLog) {
34894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        super(context);
34994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
35094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mContext = context;
35194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallFetcher = callFetcher;
35294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mContactInfoHelper = contactInfoHelper;
353c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        mIsCallLog = isCallLog;
354654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee        mCallItemExpandedListener = callItemExpandedListener;
35594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
3569686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati        mOnReportButtonClickListener = onReportButtonClickListener;
357b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati        mReportedToast = Toast.makeText(mContext, R.string.toast_caller_id_reported,
358b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati                Toast.LENGTH_SHORT);
359b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati
36094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mContactInfoCache = ExpirableCache.create(CONTACT_INFO_CACHE_SIZE);
36194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mRequests = new LinkedList<ContactInfoRequest>();
36294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
36394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        Resources resources = mContext.getResources();
36494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        CallTypeHelper callTypeHelper = new CallTypeHelper(resources);
365b2687dd09eef2fc1aaf31ea4a3edf523677108a8Andrew Lee        mCallLogBackgroundColor = resources.getColor(R.color.background_dialer_list_items);
366b2687dd09eef2fc1aaf31ea4a3edf523677108a8Andrew Lee        mExpandedBackgroundColor = resources.getColor(R.color.call_log_expanded_background_color);
367b2687dd09eef2fc1aaf31ea4a3edf523677108a8Andrew Lee        mExpandedTranslationZ = resources.getDimension(R.dimen.call_log_expanded_translation_z);
36894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
36994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mContactPhotoManager = ContactPhotoManager.getInstance(mContext);
370e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen        mPhoneNumberHelper = new PhoneNumberDisplayHelper(mContext, resources);
371e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen        mPhoneNumberUtilsWrapper = new PhoneNumberUtilsWrapper(mContext);
372e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen        PhoneCallDetailsHelper phoneCallDetailsHelper =
373e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen                new PhoneCallDetailsHelper(mContext, resources, mPhoneNumberUtilsWrapper);
37494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallLogViewsHelper =
37594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                new CallLogListItemHelper(
37694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        phoneCallDetailsHelper, mPhoneNumberHelper, resources);
37794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallLogGroupBuilder = new CallLogGroupBuilder(this);
37894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
37994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
38094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
38194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Requery on background thread when {@link Cursor} changes.
38294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
38394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
38494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    protected void onContentChanged() {
38594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallFetcher.fetchCalls();
38694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
38794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
388fb585079cc4c522c27f6dd6bf03fd296535960f3Yorke Lee    public void setLoading(boolean loading) {
38994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mLoading = loading;
39094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
39194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
39294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
39394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    public boolean isEmpty() {
39494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (mLoading) {
39594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // We don't want the empty state to show when loading.
39694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            return false;
39794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        } else {
39894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            return super.isEmpty();
39994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
40094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
40194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
40294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
40394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Starts a background thread to process contact-lookup requests, unless one
40494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * has already been started.
40594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
40694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private synchronized void startRequestProcessing() {
40794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // For unit-testing.
40894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (mRequestProcessingDisabled) return;
40994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
41094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Idempotence... if a thread is already started, don't start another.
41194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (mCallerIdThread != null) return;
41294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
41394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallerIdThread = new QueryThread();
41494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallerIdThread.setPriority(Thread.MIN_PRIORITY);
41594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallerIdThread.start();
41694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
41794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
41894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
41994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Stops the background thread that processes updates and cancels any
42094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * pending requests to start it.
42194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
42294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    public synchronized void stopRequestProcessing() {
42394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Remove any pending requests to start the processing thread.
42494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mHandler.removeMessages(START_THREAD);
42594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (mCallerIdThread != null) {
42694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // Stop the thread; we are finished with it.
42794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mCallerIdThread.stopProcessing();
42894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mCallerIdThread.interrupt();
42994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mCallerIdThread = null;
43094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
43194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
43294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
43394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
43494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Stop receiving onPreDraw() notifications.
43594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
43694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private void unregisterPreDrawListener() {
43794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (mViewTreeObserver != null && mViewTreeObserver.isAlive()) {
43894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mViewTreeObserver.removeOnPreDrawListener(this);
43994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
44094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mViewTreeObserver = null;
44194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
44294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
44394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    public void invalidateCache() {
44494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mContactInfoCache.expireAll();
44594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
44694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Restart the request-processing thread after the next draw.
44794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        stopRequestProcessing();
44894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        unregisterPreDrawListener();
44994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
45094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
45194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
45294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Enqueues a request to look up the contact details for the given phone number.
45394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
45494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * It also provides the current contact info stored in the call log for this number.
45594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
45694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * If the {@code immediate} parameter is true, it will start immediately the thread that looks
45794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * up the contact information (if it has not been already started). Otherwise, it will be
45894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * started with a delay. See {@link #START_PROCESSING_REQUESTS_DELAY_MILLIS}.
45994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
460f73d2a97203261016e6c3f35ab8ab3a4a4f4c0b7Chiao Cheng    protected void enqueueRequest(String number, String countryIso, ContactInfo callLogInfo,
46194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            boolean immediate) {
46294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        ContactInfoRequest request = new ContactInfoRequest(number, countryIso, callLogInfo);
46394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        synchronized (mRequests) {
46494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!mRequests.contains(request)) {
46594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                mRequests.add(request);
46694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                mRequests.notifyAll();
46794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
46894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
46994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (immediate) startRequestProcessing();
47094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
47194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
47294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
47394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Queries the appropriate content provider for the contact associated with the number.
47494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
47594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Upon completion it also updates the cache in the call log, if it is different from
47694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * {@code callLogInfo}.
47794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
47894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * The number might be either a SIP address or a phone number.
47994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
48094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * It returns true if it updated the content of the cache and we should therefore tell the
48194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * view to update its content.
48294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
48394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private boolean queryContactInfo(String number, String countryIso, ContactInfo callLogInfo) {
48494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final ContactInfo info = mContactInfoHelper.lookupNumber(number, countryIso);
48594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
48694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (info == null) {
48794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // The lookup failed, just return without requesting to update the view.
48894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            return false;
48994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
49094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
49194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Check the existing entry in the cache: only if it has changed we should update the
49294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // view.
49394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso);
49494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        ContactInfo existingInfo = mContactInfoCache.getPossiblyExpired(numberCountryIso);
495034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee
496934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee        final boolean isRemoteSource = info.sourceType != 0;
497934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee
498934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee        // Don't force redraw if existing info in the cache is equal to {@link ContactInfo#EMPTY}
499934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee        // to avoid updating the data set for every new row that is scrolled into view.
500934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee        // see (https://googleplex-android-review.git.corp.google.com/#/c/166680/)
501934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee
502934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee        // Exception: Photo uris for contacts from remote sources are not cached in the call log
503934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee        // cache, so we have to force a redraw for these contacts regardless.
504934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee        boolean updated = (existingInfo != ContactInfo.EMPTY || isRemoteSource) &&
505934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee                !info.equals(existingInfo);
50694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
50794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Store the data in the cache so that the UI thread can use to display it. Store it
50894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // even if it has not changed so that it is marked as not expired.
50994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mContactInfoCache.put(numberCountryIso, info);
51094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Update the call log even if the cache it is up-to-date: it is possible that the cache
51194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // contains the value from a different call log entry.
51294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        updateCallLogContactInfoCache(number, countryIso, info, callLogInfo);
51394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        return updated;
51494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
51594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
51694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /*
51794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Handles requests for contact name and number type.
51894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
51994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private class QueryThread extends Thread {
52094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        private volatile boolean mDone = false;
52194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
52294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public QueryThread() {
52394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            super("CallLogAdapter.QueryThread");
52494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
52594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
52694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public void stopProcessing() {
52794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mDone = true;
52894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
52994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
53094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        @Override
53194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public void run() {
53294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            boolean needRedraw = false;
53394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            while (true) {
53494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // Check if thread is finished, and if so return immediately.
53594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                if (mDone) return;
53694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
53794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // Obtain next request, if any is available.
53894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // Keep synchronized section small.
53994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                ContactInfoRequest req = null;
54094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                synchronized (mRequests) {
54194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    if (!mRequests.isEmpty()) {
54294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        req = mRequests.removeFirst();
54394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    }
54494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                }
54594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
54694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                if (req != null) {
54794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    // Process the request. If the lookup succeeds, schedule a
54894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    // redraw.
54994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    needRedraw |= queryContactInfo(req.number, req.countryIso, req.callLogInfo);
55094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                } else {
55194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    // Throttle redraw rate by only sending them when there are
55294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    // more requests.
55394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    if (needRedraw) {
55494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        needRedraw = false;
55594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        mHandler.sendEmptyMessage(REDRAW);
55694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    }
55794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
55894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    // Wait until another request is available, or until this
55994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    // thread is no longer needed (as indicated by being
56094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    // interrupted).
56194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    try {
56294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        synchronized (mRequests) {
56394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                            mRequests.wait(1000);
56494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        }
56594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    } catch (InterruptedException ie) {
56694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        // Ignore, and attempt to continue processing requests.
56794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    }
56894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                }
56994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
57094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
57194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
57294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
57394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
57494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    protected void addGroups(Cursor cursor) {
57594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallLogGroupBuilder.addGroups(cursor);
57694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
57794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
57894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
57994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    protected View newStandAloneView(Context context, ViewGroup parent) {
580704acc087ce359295475a46695c2821c55778344Chiao Cheng        return newChildView(context, parent);
58194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
58294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
58394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
584704acc087ce359295475a46695c2821c55778344Chiao Cheng    protected View newGroupView(Context context, ViewGroup parent) {
585704acc087ce359295475a46695c2821c55778344Chiao Cheng        return newChildView(context, parent);
58694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
58794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
58894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
58994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    protected View newChildView(Context context, ViewGroup parent) {
590c329bfb6d47f20237d22e13297d5bbb72e612919Evan Charlton        LayoutInflater inflater = LayoutInflater.from(context);
591b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee        CallLogListItemView view =
592b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee                (CallLogListItemView) inflater.inflate(R.layout.call_log_list_item, parent, false);
593c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee
594c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee        // Get the views to bind to and cache them.
595c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee        CallLogListItemViews views = CallLogListItemViews.fromView(view);
596c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee        view.setTag(views);
597c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee
598c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee        // Set text height to false on the TextViews so they don't have extra padding.
599c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee        views.phoneCallDetailsViews.nameView.setElegantTextHeight(false);
600c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee        views.phoneCallDetailsViews.callLocationAndDate.setElegantTextHeight(false);
601c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee
60294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        return view;
60394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
60494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
60594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
606704acc087ce359295475a46695c2821c55778344Chiao Cheng    protected void bindStandAloneView(View view, Context context, Cursor cursor) {
60794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        bindView(view, cursor, 1);
60894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
60994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
61094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
611704acc087ce359295475a46695c2821c55778344Chiao Cheng    protected void bindChildView(View view, Context context, Cursor cursor) {
612704acc087ce359295475a46695c2821c55778344Chiao Cheng        bindView(view, cursor, 1);
61394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
61494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
61594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
61694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    protected void bindGroupView(View view, Context context, Cursor cursor, int groupSize,
61794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            boolean expanded) {
61894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        bindView(view, cursor, groupSize);
61994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
62094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
62194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private void findAndCacheViews(View view) {
62294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
62394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
62494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
62594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Binds the views in the entry to the data in the call log.
62694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     *
62794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * @param view the view corresponding to this entry
62894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * @param c the cursor pointing to the entry in the call log
62994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * @param count the number of entries in the current item, greater than 1 if it is a group
63094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
63194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private void bindView(View view, Cursor c, int count) {
632b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee        view.setAccessibilityDelegate(mAccessibilityDelegate);
6338ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn        final CallLogListItemView callLogItemView = (CallLogListItemView) view;
63494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final CallLogListItemViews views = (CallLogListItemViews) view.getTag();
635f517e7bb367d1ed749b500959d0a0a1ba8c3d5e5Christine Chen
63694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Default case: an item in the call log.
63794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        views.primaryActionView.setVisibility(View.VISIBLE);
63894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
63994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final String number = c.getString(CallLogQuery.NUMBER);
640719a7adde25e0a717816b00668c16c3a1e3c5518Jay Shrauner        final int numberPresentation = c.getInt(CallLogQuery.NUMBER_PRESENTATION);
64194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final long date = c.getLong(CallLogQuery.DATE);
64294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final long duration = c.getLong(CallLogQuery.DURATION);
64394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final int callType = c.getInt(CallLogQuery.CALL_TYPE);
644b2eebafbc1f1e26b5178b2858ca335467b4bc341Nancy Chen        final PhoneAccountHandle accountHandle = PhoneAccountUtils.getAccount(
645b2eebafbc1f1e26b5178b2858ca335467b4bc341Nancy Chen                c.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME),
646b2eebafbc1f1e26b5178b2858ca335467b4bc341Nancy Chen                c.getString(CallLogQuery.ACCOUNT_ID));
64794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final String countryIso = c.getString(CallLogQuery.COUNTRY_ISO);
6488cd9423bd04584acbcbf178bf6a1c1953debb8daYorke Lee
649146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        final long rowId = c.getLong(CallLogQuery.ID);
650146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        views.rowId = rowId;
651146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
6524dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        // For entries in the call log, check if the day group has changed and display a header
6534dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        // if necessary.
6544dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        if (mIsCallLog) {
6554dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            int currentGroup = getDayGroupForCall(rowId);
6564dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            int previousGroup = getPreviousDayGroup(c);
6574dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            if (currentGroup != previousGroup) {
6584dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn                views.dayGroupHeader.setVisibility(View.VISIBLE);
6594dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn                views.dayGroupHeader.setText(getGroupDescription(currentGroup));
6604dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            } else {
6614dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn                views.dayGroupHeader.setVisibility(View.GONE);
6624dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            }
6634dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        } else {
6644dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            views.dayGroupHeader.setVisibility(View.GONE);
6654dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        }
6664dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn
667146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // Store some values used when the actions ViewStub is inflated on expansion of the actions
668146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // section.
669146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        views.number = number;
670146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        views.numberPresentation = numberPresentation;
671146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        views.callType = callType;
6728f7c4368817a17727b2132d399d0895e33f67a95Nancy Chen        // NOTE: This is currently not being used, but can be used in future versions.
6738f7c4368817a17727b2132d399d0895e33f67a95Nancy Chen        views.accountHandle = accountHandle;
674146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        views.voicemailUri = c.getString(CallLogQuery.VOICEMAIL_URI);
675146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // Stash away the Ids of the calls so that we can support deleting a row in the call log.
676cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn        views.callIds = getCallIds(c, count);
67794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
67894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final ContactInfo cachedContactInfo = getContactInfoFromCallLog(c);
67994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
68056cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        final boolean isVoicemailNumber =
681e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen                mPhoneNumberUtilsWrapper.isVoicemailNumber(accountHandle, number);
68256cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee
683146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // Where binding and not in the call log, use default behaviour of invoking a call when
684146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // tapping the primary view.
685146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        if (!mIsCallLog) {
686146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.primaryActionView.setOnClickListener(this.mActionListener);
687fb585079cc4c522c27f6dd6bf03fd296535960f3Yorke Lee
688146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            // Set return call intent, otherwise null.
689146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            if (PhoneNumberUtilsWrapper.canPlaceCallsTo(number, numberPresentation)) {
690146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn                // Sets the primary action to call the number.
6918f7c4368817a17727b2132d399d0895e33f67a95Nancy Chen                views.primaryActionView.setTag(IntentProvider.getReturnCallIntentProvider(number));
69245ed3b5932ed590b45235d7b2befa736a95e7f75Tyler Gunn            } else {
693146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn                // Number is not callable, so hide button.
694146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn                views.primaryActionView.setTag(null);
69545ed3b5932ed590b45235d7b2befa736a95e7f75Tyler Gunn            }
69694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        } else {
697146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            // In the call log, expand/collapse an actions section for the call log entry when
698146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            // the primary view is tapped.
699146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.primaryActionView.setOnClickListener(this.mExpandCollapseListener);
700146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
701146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            // Note: Binding of the action buttons is done as required in configureActionViews
702146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            // when the user expands the actions ViewStub.
703146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
704146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
70594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Lookup contacts with this number
70694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso);
70794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        ExpirableCache.CachedValue<ContactInfo> cachedInfo =
70894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                mContactInfoCache.getCachedValue(numberCountryIso);
70994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        ContactInfo info = cachedInfo == null ? null : cachedInfo.getValue();
710fb0a934ad90f1855787563eb80f2c8fff7f640acChiao Cheng        if (!PhoneNumberUtilsWrapper.canPlaceCallsTo(number, numberPresentation)
71156cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee                || isVoicemailNumber) {
71294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // If this is a number that cannot be dialed, there is no point in looking up a contact
71394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // for it.
71494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            info = ContactInfo.EMPTY;
71594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        } else if (cachedInfo == null) {
71694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mContactInfoCache.put(numberCountryIso, ContactInfo.EMPTY);
71794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // Use the cached contact info from the call log.
71894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            info = cachedContactInfo;
71994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // The db request should happen on a non-UI thread.
72094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // Request the contact details immediately since they are currently missing.
72194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            enqueueRequest(number, countryIso, cachedContactInfo, true);
72294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // We will format the phone number when we make the background request.
72394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        } else {
72494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (cachedInfo.isExpired()) {
72594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // The contact info is no longer up to date, we should request it. However, we
72694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // do not need to request them immediately.
72794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                enqueueRequest(number, countryIso, cachedContactInfo, false);
72894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            } else  if (!callLogInfoMatches(cachedContactInfo, info)) {
72994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // The call log information does not match the one we have, look it up again.
73094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // We could simply update the call log directly, but that needs to be done in a
73194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // background thread, so it is easier to simply request a new lookup, which will, as
73294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // a side-effect, update the call log.
73394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                enqueueRequest(number, countryIso, cachedContactInfo, false);
73494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
73594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
73694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (info == ContactInfo.EMPTY) {
73794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // Use the cached contact info from the call log.
73894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                info = cachedContactInfo;
73994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
74094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
74194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
74294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final Uri lookupUri = info.lookupUri;
74394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final String name = info.name;
74494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final int ntype = info.type;
74594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final String label = info.label;
74694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final long photoId = info.photoId;
747034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee        final Uri photoUri = info.photoUri;
74894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        CharSequence formattedNumber = info.formattedNumber;
74994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final int[] callTypes = getCallTypes(c, count);
75094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final String geocode = c.getString(CallLogQuery.GEOCODED_LOCATION);
75156cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        final int sourceType = info.sourceType;
7528b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        final int features = getCallFeatures(c, count);
7538cd9423bd04584acbcbf178bf6a1c1953debb8daYorke Lee        final String transcription = c.getString(CallLogQuery.TRANSCRIPTION);
7548b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        Long dataUsage = null;
7558b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        if (!c.isNull(CallLogQuery.DATA_USAGE)) {
7568b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn            dataUsage = c.getLong(CallLogQuery.DATA_USAGE);
7578b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        }
7588b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn
75994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final PhoneCallDetails details;
760704acc087ce359295475a46695c2821c55778344Chiao Cheng
761b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati        views.reported = info.isBadData;
76255733814f213809baaa8eaa8984ff026bdb08b4eAnthony Lee
76355733814f213809baaa8eaa8984ff026bdb08b4eAnthony Lee        // The entry can only be reported as invalid if it has a valid ID and the source of the
76455733814f213809baaa8eaa8984ff026bdb08b4eAnthony Lee        // entry supports marking entries as invalid.
76555733814f213809baaa8eaa8984ff026bdb08b4eAnthony Lee        views.canBeReportedAsInvalid = mContactInfoHelper.canReportAsInvalid(info.sourceType,
76655733814f213809baaa8eaa8984ff026bdb08b4eAnthony Lee                info.objectId);
767b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati
7689686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati        // Restore expansion state of the row on rebind.  Inflate the actions ViewStub if required,
7699686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati        // and set its visibility state accordingly.
7709686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati        expandOrCollapseActions(callLogItemView, isExpanded(rowId));
7719686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati
77294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (TextUtils.isEmpty(name)) {
773e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen            details = new PhoneCallDetails(number, numberPresentation, formattedNumber, countryIso,
774e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen                    geocode, callTypes, date, duration, accountHandle, features, dataUsage,
775e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen                    transcription);
77694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        } else {
777e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen            details = new PhoneCallDetails(number, numberPresentation, formattedNumber, countryIso,
778e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen                    geocode, callTypes, date, duration, name, ntype, label, lookupUri, photoUri,
779e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen                    sourceType, accountHandle, features, dataUsage, transcription);
78094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
78194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
7820927dc6ef623bec56415d087885f6d2607da35f7Andrew Lee        mCallLogViewsHelper.setPhoneCallDetails(mContext, views, details);
783034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee
78456cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        int contactType = ContactPhotoManager.TYPE_DEFAULT;
78556cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee
78656cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        if (isVoicemailNumber) {
78756cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee            contactType = ContactPhotoManager.TYPE_VOICEMAIL;
78856cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        } else if (mContactInfoHelper.isBusiness(info.sourceType)) {
78956cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee            contactType = ContactPhotoManager.TYPE_BUSINESS;
79056cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        }
79156cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee
792a5804f5b62bd87a0c8a35d7651a6862ecc1f220bYorke Lee        String lookupKey = lookupUri == null ? null
793a5804f5b62bd87a0c8a35d7651a6862ecc1f220bYorke Lee                : ContactInfoHelper.getLookupKeyFromUri(lookupUri);
79456cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee
79556cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        String nameForDefaultImage = null;
79656cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        if (TextUtils.isEmpty(name)) {
797e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen            nameForDefaultImage = mPhoneNumberHelper.getDisplayNumber(details.accountHandle,
798e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen                    details.number, details.numberPresentation, details.formattedNumber).toString();
79956cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        } else {
80056cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee            nameForDefaultImage = name;
80156cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        }
80256cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee
803034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee        if (photoId == 0 && photoUri != null) {
80456cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee            setPhoto(views, photoUri, lookupUri, nameForDefaultImage, lookupKey, contactType);
805034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee        } else {
80656cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee            setPhoto(views, photoId, lookupUri, nameForDefaultImage, lookupKey, contactType);
807034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee        }
80894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
80994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Listen for the first draw
81094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (mViewTreeObserver == null) {
81194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mViewTreeObserver = view.getViewTreeObserver();
81294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mViewTreeObserver.addOnPreDrawListener(this);
81394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
814704acc087ce359295475a46695c2821c55778344Chiao Cheng
815c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        bindBadge(view, info, details, callType);
816c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    }
817c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
818146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /**
8194dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * Retrieves the day group of the previous call in the call log.  Used to determine if the day
8204dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * group has changed and to trigger display of the day group text.
8214dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *
8224dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @param cursor The call log cursor.
8234dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @return The previous day group, or DAY_GROUP_NONE if this is the first call.
8244dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     */
8254dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    private int getPreviousDayGroup(Cursor cursor) {
8264dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        // We want to restore the position in the cursor at the end.
8274dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        int startingPosition = cursor.getPosition();
8284dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        int dayGroup = CallLogGroupBuilder.DAY_GROUP_NONE;
8294dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        if (cursor.moveToPrevious()) {
8304dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            long previousRowId = cursor.getLong(CallLogQuery.ID);
8314dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            dayGroup = getDayGroupForCall(previousRowId);
8324dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        }
8334dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        cursor.moveToPosition(startingPosition);
8344dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        return dayGroup;
8354dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    }
8364dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn
8374dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    /**
8384dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * Given a call Id, look up the day group that the call belongs to.  The day group data is
8394dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * populated in {@link com.android.dialer.calllog.CallLogGroupBuilder}.
8404dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *
8414dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @param callId The call to retrieve the day group for.
8424dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @return The day group for the call.
8434dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     */
8444dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    private int getDayGroupForCall(long callId) {
8454dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        if (mDayGroups.containsKey(callId)) {
8464dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            return mDayGroups.get(callId);
8474dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        }
8484dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        return CallLogGroupBuilder.DAY_GROUP_NONE;
8494dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    }
8504dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    /**
8518ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     * Determines if a call log row with the given Id is expanded.
8528ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     * @param rowId The row Id of the call.
8538ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     * @return True if the row should be expanded.
854146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     */
855146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    private boolean isExpanded(long rowId) {
8568ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn        return mCurrentlyExpanded == rowId;
857146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    }
858146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
859146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /**
860146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * Toggles the expansion state tracked for the call log row identified by rowId and returns
8618ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     * the new expansion state.  Assumes that only a single call log row will be expanded at any
8628ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     * one point and tracks the current and previous expanded item.
863146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     *
864146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * @param rowId The row Id associated with the call log row to expand/collapse.
865146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * @return True where the row is now expanded, false otherwise.
866146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     */
867146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    private boolean toggleExpansion(long rowId) {
8688ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn        if (rowId == mCurrentlyExpanded) {
8698ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            // Collapsing currently expanded row.
8708ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            mPreviouslyExpanded = NONE_EXPANDED;
8718ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            mCurrentlyExpanded = NONE_EXPANDED;
872146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
8738ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            return false;
8748ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn        } else {
8758ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            // Expanding a row (collapsing current expanded one).
8768ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn
87768e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn            mPreviouslyExpanded = mCurrentlyExpanded;
8788ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            mCurrentlyExpanded = rowId;
8798ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            return true;
8808ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn        }
881146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    }
882146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
883146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /**
8849138834059797469f73390c9faa71ce98b4434c1Tyler Gunn     * Expands or collapses the view containing the CALLBACK, VOICEMAIL and DETAILS action buttons.
885146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     *
886146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * @param callLogItem The call log entry parent view.
8877be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn     * @param isExpanded The new expansion state of the view.
888146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     */
8898ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn    private void expandOrCollapseActions(CallLogListItemView callLogItem, boolean isExpanded) {
890146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        final CallLogListItemViews views = (CallLogListItemViews)callLogItem.getTag();
891146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
892f42ea913f3569e0bef2ae18404b29610f368cc77Yorke Lee        expandVoicemailTranscriptionView(views, isExpanded);
8937be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn        if (isExpanded) {
8947be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn            // Inflate the view stub if necessary, and wire up the event handlers.
8957be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn            inflateActionViewStub(callLogItem);
896146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
897146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.actionsView.setVisibility(View.VISIBLE);
8988ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            views.actionsView.setAlpha(1.0f);
899b2687dd09eef2fc1aaf31ea4a3edf523677108a8Andrew Lee            views.callLogEntryView.setBackgroundColor(mExpandedBackgroundColor);
9000d8019cf7cb048e5da044559460e08c5284d8f48Chris Craik            views.callLogEntryView.setTranslationZ(mExpandedTranslationZ);
9010d8019cf7cb048e5da044559460e08c5284d8f48Chris Craik            callLogItem.setTranslationZ(mExpandedTranslationZ); // WAR
902146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        } else {
9037be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn            // When recycling a view, it is possible the actionsView ViewStub was previously
9047be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn            // inflated so we should hide it in this case.
9058ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            if (views.actionsView != null) {
9067be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn                views.actionsView.setVisibility(View.GONE);
9077be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn            }
9087be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn
909b2687dd09eef2fc1aaf31ea4a3edf523677108a8Andrew Lee            views.callLogEntryView.setBackgroundColor(mCallLogBackgroundColor);
9100d8019cf7cb048e5da044559460e08c5284d8f48Chris Craik            views.callLogEntryView.setTranslationZ(0);
9110d8019cf7cb048e5da044559460e08c5284d8f48Chris Craik            callLogItem.setTranslationZ(0); // WAR
912146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
913146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    }
914146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
915f42ea913f3569e0bef2ae18404b29610f368cc77Yorke Lee    public static void expandVoicemailTranscriptionView(CallLogListItemViews views,
916f42ea913f3569e0bef2ae18404b29610f368cc77Yorke Lee            boolean isExpanded) {
917f42ea913f3569e0bef2ae18404b29610f368cc77Yorke Lee        if (views.callType != Calls.VOICEMAIL_TYPE) {
918f42ea913f3569e0bef2ae18404b29610f368cc77Yorke Lee            return;
919f42ea913f3569e0bef2ae18404b29610f368cc77Yorke Lee        }
920f42ea913f3569e0bef2ae18404b29610f368cc77Yorke Lee
921f42ea913f3569e0bef2ae18404b29610f368cc77Yorke Lee        final TextView view = views.phoneCallDetailsViews.voicemailTranscriptionView;
922f42ea913f3569e0bef2ae18404b29610f368cc77Yorke Lee        if (TextUtils.isEmpty(view.getText())) {
923f42ea913f3569e0bef2ae18404b29610f368cc77Yorke Lee            return;
924f42ea913f3569e0bef2ae18404b29610f368cc77Yorke Lee        }
925f42ea913f3569e0bef2ae18404b29610f368cc77Yorke Lee        view.setMaxLines(isExpanded ? VOICEMAIL_TRANSCRIPTION_MAX_LINES : 1);
926f42ea913f3569e0bef2ae18404b29610f368cc77Yorke Lee        view.setSingleLine(!isExpanded);
927f42ea913f3569e0bef2ae18404b29610f368cc77Yorke Lee    }
928f42ea913f3569e0bef2ae18404b29610f368cc77Yorke Lee
929146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /**
930146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * Configures the action buttons in the expandable actions ViewStub.  The ViewStub is not
931146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * inflated during initial binding, so click handlers, tags and accessibility text must be set
932146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * here, if necessary.
933146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     *
934146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * @param callLogItem The call log list item view.
935146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     */
936b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati    private void inflateActionViewStub(final View callLogItem) {
937146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        final CallLogListItemViews views = (CallLogListItemViews)callLogItem.getTag();
938146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
939146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        ViewStub stub = (ViewStub)callLogItem.findViewById(R.id.call_log_entry_actions_stub);
940146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        if (stub != null) {
941b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee            views.actionsView = (ViewGroup) stub.inflate();
942146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
943146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
944146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        if (views.callBackButtonView == null) {
9458ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            views.callBackButtonView = (TextView)views.actionsView.findViewById(
9468ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn                    R.id.call_back_action);
947146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
948146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
9495619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn        if (views.videoCallButtonView == null) {
9505619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn            views.videoCallButtonView = (TextView)views.actionsView.findViewById(
9515619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn                    R.id.video_call_action);
9525619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn        }
9535619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn
954146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        if (views.voicemailButtonView == null) {
9558ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            views.voicemailButtonView = (TextView)views.actionsView.findViewById(
9568ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn                    R.id.voicemail_action);
957146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
958146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
959cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn        if (views.detailsButtonView == null) {
960cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn            views.detailsButtonView = (TextView)views.actionsView.findViewById(R.id.details_action);
961cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn        }
962cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn
963b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati        if (views.reportButtonView == null) {
964b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati            views.reportButtonView = (TextView)views.actionsView.findViewById(R.id.report_action);
965b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati            views.reportButtonView.setOnClickListener(new View.OnClickListener() {
966b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati                @Override
967b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati                public void onClick(View v) {
9689686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati                    if (mOnReportButtonClickListener != null) {
9699686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati                        mOnReportButtonClickListener.onReportButtonClick(views.number);
9709686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati                    }
971b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati                }
972b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati            });
973b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati        }
974b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati
975146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        bindActionButtons(views);
976146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    }
977146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
978146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /***
9799138834059797469f73390c9faa71ce98b4434c1Tyler Gunn     * Binds click handlers and intents to the voicemail, details and callback action buttons.
980146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     *
981146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * @param views  The call log item views.
982146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     */
983146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    private void bindActionButtons(CallLogListItemViews views) {
9845619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn        boolean canPlaceCallToNumber =
9855619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn                PhoneNumberUtilsWrapper.canPlaceCallsTo(views.number, views.numberPresentation);
986146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // Set return call intent, otherwise null.
9875619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn        if (canPlaceCallToNumber) {
988146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            // Sets the primary action to call the number.
989146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.callBackButtonView.setTag(
9908f7c4368817a17727b2132d399d0895e33f67a95Nancy Chen                    IntentProvider.getReturnCallIntentProvider(views.number));
991146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.callBackButtonView.setVisibility(View.VISIBLE);
992146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.callBackButtonView.setOnClickListener(mActionListener);
993146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        } else {
994146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            // Number is not callable, so hide button.
995146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.callBackButtonView.setTag(null);
996146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.callBackButtonView.setVisibility(View.GONE);
997146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
998146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
9995619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn        // If one of the calls had video capabilities, show the video call button.
1000ac7f2354a58bac2099b6a9442f6c8388fcf1c148Tyler Gunn        if (CallUtil.isVideoEnabled(mContext) && canPlaceCallToNumber &&
1001ac7f2354a58bac2099b6a9442f6c8388fcf1c148Tyler Gunn                views.phoneCallDetailsViews.callTypeIcons.isVideoShown()) {
10025619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn            views.videoCallButtonView.setTag(
10038f7c4368817a17727b2132d399d0895e33f67a95Nancy Chen                    IntentProvider.getReturnVideoCallIntentProvider(views.number));
10045619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn            views.videoCallButtonView.setVisibility(View.VISIBLE);
10055619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn            views.videoCallButtonView.setOnClickListener(mActionListener);
10065619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn        } else {
10075619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn            views.videoCallButtonView.setTag(null);
10085619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn            views.videoCallButtonView.setVisibility(View.GONE);
10095619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn        }
10105619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn
1011146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // For voicemail calls, show the "VOICEMAIL" action button; hide otherwise.
1012146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        if (views.callType == Calls.VOICEMAIL_TYPE) {
1013146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.voicemailButtonView.setOnClickListener(mActionListener);
1014146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.voicemailButtonView.setTag(
1015146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn                    IntentProvider.getPlayVoicemailIntentProvider(
1016146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn                            views.rowId, views.voicemailUri));
1017146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.voicemailButtonView.setVisibility(View.VISIBLE);
1018cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn
1019cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn            views.detailsButtonView.setVisibility(View.GONE);
1020146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        } else {
1021146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.voicemailButtonView.setTag(null);
1022146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.voicemailButtonView.setVisibility(View.GONE);
1023cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn
1024cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn            views.detailsButtonView.setOnClickListener(mActionListener);
1025cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn            views.detailsButtonView.setTag(
1026cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn                    IntentProvider.getCallDetailIntentProvider(
1027cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn                            views.rowId, views.callIds, null)
1028cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn            );
10295619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn
103055733814f213809baaa8eaa8984ff026bdb08b4eAnthony Lee            if (views.canBeReportedAsInvalid && !views.reported) {
1031b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati                views.reportButtonView.setVisibility(View.VISIBLE);
10329686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati            } else {
10339686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati                views.reportButtonView.setVisibility(View.GONE);
1034b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati            }
1035146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
1036146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
1037146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        mCallLogViewsHelper.setActionContentDescriptions(views);
1038146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    }
1039146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
1040eb141e078353a2e3a997001afd1aa16a88da429bAndrew Lee    protected void bindBadge(
1041eb141e078353a2e3a997001afd1aa16a88da429bAndrew Lee            View view, ContactInfo info, final PhoneCallDetails details, int callType) {
1042c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        // Do not show badge in call log.
1043c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        if (!mIsCallLog) {
1044c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            final ViewStub stub = (ViewStub) view.findViewById(R.id.link_stub);
10456b88e54849d5563386d51f5d338e37fc1e4b459fYorke Lee            if (UriUtils.isEncodedContactUri(info.lookupUri)) {
1046c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                if (stub != null) {
1047c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                    final View inflated = stub.inflate();
1048c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                    inflated.setVisibility(View.VISIBLE);
1049c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                    mBadgeContainer = inflated.findViewById(R.id.badge_link_container);
1050c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                    mBadgeImageView = (ImageView) inflated.findViewById(R.id.badge_image);
1051c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                    mBadgeText = (TextView) inflated.findViewById(R.id.badge_text);
1052c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                }
1053c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
1054eb141e078353a2e3a997001afd1aa16a88da429bAndrew Lee                mBadgeContainer.setOnClickListener(new View.OnClickListener() {
1055eb141e078353a2e3a997001afd1aa16a88da429bAndrew Lee                    @Override
1056eb141e078353a2e3a997001afd1aa16a88da429bAndrew Lee                    public void onClick(View v) {
1057eb141e078353a2e3a997001afd1aa16a88da429bAndrew Lee                        final Intent intent =
1058eb141e078353a2e3a997001afd1aa16a88da429bAndrew Lee                                DialtactsActivity.getAddNumberToContactIntent(details.number);
1059eb141e078353a2e3a997001afd1aa16a88da429bAndrew Lee                        mContext.startActivity(intent);
1060eb141e078353a2e3a997001afd1aa16a88da429bAndrew Lee                    }
1061eb141e078353a2e3a997001afd1aa16a88da429bAndrew Lee                });
1062eb141e078353a2e3a997001afd1aa16a88da429bAndrew Lee                mBadgeImageView.setImageResource(R.drawable.ic_person_add_24dp);
1063eb141e078353a2e3a997001afd1aa16a88da429bAndrew Lee                mBadgeText.setText(R.string.recentCalls_addToContact);
1064c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            } else {
1065c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                // Hide badge if it was previously shown.
1066c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                if (stub == null) {
1067c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                    final View container = view.findViewById(R.id.badge_container);
1068c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                    if (container != null) {
1069c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                        container.setVisibility(View.GONE);
1070c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                    }
1071c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                }
1072c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            }
1073c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        }
1074c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    }
1075c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
107694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Checks whether the contact info from the call log matches the one from the contacts db. */
107794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private boolean callLogInfoMatches(ContactInfo callLogInfo, ContactInfo info) {
107894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // The call log only contains a subset of the fields in the contacts db.
107994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Only check those.
108094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        return TextUtils.equals(callLogInfo.name, info.name)
108194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                && callLogInfo.type == info.type
108294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                && TextUtils.equals(callLogInfo.label, info.label);
108394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
108494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
108594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Stores the updated contact info in the call log if it is different from the current one. */
108694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private void updateCallLogContactInfoCache(String number, String countryIso,
108794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            ContactInfo updatedInfo, ContactInfo callLogInfo) {
108894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final ContentValues values = new ContentValues();
108994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        boolean needsUpdate = false;
109094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
109194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (callLogInfo != null) {
109294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!TextUtils.equals(updatedInfo.name, callLogInfo.name)) {
109394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                values.put(Calls.CACHED_NAME, updatedInfo.name);
109494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                needsUpdate = true;
109594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
109694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
109794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (updatedInfo.type != callLogInfo.type) {
109894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                values.put(Calls.CACHED_NUMBER_TYPE, updatedInfo.type);
109994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                needsUpdate = true;
110094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
110194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
110294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!TextUtils.equals(updatedInfo.label, callLogInfo.label)) {
110394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                values.put(Calls.CACHED_NUMBER_LABEL, updatedInfo.label);
110494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                needsUpdate = true;
110594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
110694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!UriUtils.areEqual(updatedInfo.lookupUri, callLogInfo.lookupUri)) {
110794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                values.put(Calls.CACHED_LOOKUP_URI, UriUtils.uriToString(updatedInfo.lookupUri));
110894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                needsUpdate = true;
110994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
1110746dba885dc50c9f723456b01cfc7dbfcc9a49b0Tyler Gunn            // Only replace the normalized number if the new updated normalized number isn't empty.
1111746dba885dc50c9f723456b01cfc7dbfcc9a49b0Tyler Gunn            if (!TextUtils.isEmpty(updatedInfo.normalizedNumber) &&
1112746dba885dc50c9f723456b01cfc7dbfcc9a49b0Tyler Gunn                    !TextUtils.equals(updatedInfo.normalizedNumber, callLogInfo.normalizedNumber)) {
111394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                values.put(Calls.CACHED_NORMALIZED_NUMBER, updatedInfo.normalizedNumber);
111494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                needsUpdate = true;
111594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
111694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!TextUtils.equals(updatedInfo.number, callLogInfo.number)) {
111794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                values.put(Calls.CACHED_MATCHED_NUMBER, updatedInfo.number);
111894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                needsUpdate = true;
111994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
112094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (updatedInfo.photoId != callLogInfo.photoId) {
112194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                values.put(Calls.CACHED_PHOTO_ID, updatedInfo.photoId);
112294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                needsUpdate = true;
112394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
112494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!TextUtils.equals(updatedInfo.formattedNumber, callLogInfo.formattedNumber)) {
112594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                values.put(Calls.CACHED_FORMATTED_NUMBER, updatedInfo.formattedNumber);
112694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                needsUpdate = true;
112794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
112894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        } else {
112994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // No previous values, store all of them.
113094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            values.put(Calls.CACHED_NAME, updatedInfo.name);
113194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            values.put(Calls.CACHED_NUMBER_TYPE, updatedInfo.type);
113294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            values.put(Calls.CACHED_NUMBER_LABEL, updatedInfo.label);
113394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            values.put(Calls.CACHED_LOOKUP_URI, UriUtils.uriToString(updatedInfo.lookupUri));
113494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            values.put(Calls.CACHED_MATCHED_NUMBER, updatedInfo.number);
113594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            values.put(Calls.CACHED_NORMALIZED_NUMBER, updatedInfo.normalizedNumber);
113694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            values.put(Calls.CACHED_PHOTO_ID, updatedInfo.photoId);
113794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            values.put(Calls.CACHED_FORMATTED_NUMBER, updatedInfo.formattedNumber);
113894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            needsUpdate = true;
113994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
114094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
114194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (!needsUpdate) return;
114294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
114394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (countryIso == null) {
114494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mContext.getContentResolver().update(Calls.CONTENT_URI_WITH_VOICEMAIL, values,
114594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    Calls.NUMBER + " = ? AND " + Calls.COUNTRY_ISO + " IS NULL",
114694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    new String[]{ number });
114794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        } else {
114894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mContext.getContentResolver().update(Calls.CONTENT_URI_WITH_VOICEMAIL, values,
114994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    Calls.NUMBER + " = ? AND " + Calls.COUNTRY_ISO + " = ?",
115094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    new String[]{ number, countryIso });
115194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
115294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
115394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
115494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Returns the contact information as stored in the call log. */
115594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private ContactInfo getContactInfoFromCallLog(Cursor c) {
115694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        ContactInfo info = new ContactInfo();
115794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        info.lookupUri = UriUtils.parseUriOrNull(c.getString(CallLogQuery.CACHED_LOOKUP_URI));
115894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        info.name = c.getString(CallLogQuery.CACHED_NAME);
115994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        info.type = c.getInt(CallLogQuery.CACHED_NUMBER_TYPE);
116094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        info.label = c.getString(CallLogQuery.CACHED_NUMBER_LABEL);
116194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        String matchedNumber = c.getString(CallLogQuery.CACHED_MATCHED_NUMBER);
116294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        info.number = matchedNumber == null ? c.getString(CallLogQuery.NUMBER) : matchedNumber;
116394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        info.normalizedNumber = c.getString(CallLogQuery.CACHED_NORMALIZED_NUMBER);
116494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        info.photoId = c.getLong(CallLogQuery.CACHED_PHOTO_ID);
116594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        info.photoUri = null;  // We do not cache the photo URI.
116694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        info.formattedNumber = c.getString(CallLogQuery.CACHED_FORMATTED_NUMBER);
116794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        return info;
116894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
116994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
117094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
117194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Returns the call types for the given number of items in the cursor.
117294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
117394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * It uses the next {@code count} rows in the cursor to extract the types.
117494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
117594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * It position in the cursor is unchanged by this function.
117694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
117794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private int[] getCallTypes(Cursor cursor, int count) {
117894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        int position = cursor.getPosition();
117994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        int[] callTypes = new int[count];
118094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        for (int index = 0; index < count; ++index) {
118194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            callTypes[index] = cursor.getInt(CallLogQuery.CALL_TYPE);
118294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            cursor.moveToNext();
118394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
118494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        cursor.moveToPosition(position);
118594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        return callTypes;
118694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
118794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
11888b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn    /**
11898b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     * Determine the features which were enabled for any of the calls that make up a call log
11908b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     * entry.
11918b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     *
11928b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     * @param cursor The cursor.
11938b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     * @param count The number of calls for the current call log entry.
11948b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     * @return The features.
11958b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     */
11968b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn    private int getCallFeatures(Cursor cursor, int count) {
119703610993bf2adf12a6962c32851095551ffd0043Yorke Lee        int features = 0;
11988b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        int position = cursor.getPosition();
11998b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        for (int index = 0; index < count; ++index) {
12008b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn            features |= cursor.getInt(CallLogQuery.FEATURES);
12018b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn            cursor.moveToNext();
12028b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        }
12038b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        cursor.moveToPosition(position);
12048b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        return features;
12058b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn    }
12068b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn
120756cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee    private void setPhoto(CallLogListItemViews views, long photoId, Uri contactUri,
120856cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee            String displayName, String identifier, int contactType) {
120994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        views.quickContactView.assignContactUri(contactUri);
1210cb481aa46e012d1f9f147919b346fbfb16624dabYorke Lee        views.quickContactView.setOverlay(null);
121156cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        DefaultImageRequest request = new DefaultImageRequest(displayName, identifier,
1212cb481aa46e012d1f9f147919b346fbfb16624dabYorke Lee                contactType, true /* isCircular */);
121356cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        mContactPhotoManager.loadThumbnail(views.quickContactView, photoId, false /* darkTheme */,
1214cb481aa46e012d1f9f147919b346fbfb16624dabYorke Lee                true /* isCircular */, request);
121594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
121694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
121756cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee    private void setPhoto(CallLogListItemViews views, Uri photoUri, Uri contactUri,
121856cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee            String displayName, String identifier, int contactType) {
1219034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee        views.quickContactView.assignContactUri(contactUri);
1220cb481aa46e012d1f9f147919b346fbfb16624dabYorke Lee        views.quickContactView.setOverlay(null);
122156cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        DefaultImageRequest request = new DefaultImageRequest(displayName, identifier,
1222cb481aa46e012d1f9f147919b346fbfb16624dabYorke Lee                contactType, true /* isCircular */);
1223034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee        mContactPhotoManager.loadDirectoryPhoto(views.quickContactView, photoUri,
1224cb481aa46e012d1f9f147919b346fbfb16624dabYorke Lee                false /* darkTheme */, true /* isCircular */, request);
1225034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee    }
1226034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee
1227d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn    /**
1228d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn     * Bind a call log entry view for testing purposes.  Also inflates the action view stub so
1229d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn     * unit tests can access the buttons contained within.
1230d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn     *
1231d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn     * @param view The current call log row.
1232d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn     * @param context The current context.
1233d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn     * @param cursor The cursor to bind from.
1234d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn     */
1235d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn    @VisibleForTesting
1236d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn    void bindViewForTest(View view, Context context, Cursor cursor) {
1237d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn        bindStandAloneView(view, context, cursor);
1238d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn        inflateActionViewStub(view);
1239d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn    }
1240034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee
124194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
124294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Sets whether processing of requests for contact details should be enabled.
124394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
124494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * This method should be called in tests to disable such processing of requests when not
124594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * needed.
124694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
124794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @VisibleForTesting
124894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    void disableRequestProcessingForTest() {
124994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mRequestProcessingDisabled = true;
125094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
125194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
125294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @VisibleForTesting
125394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    void injectContactInfoForTest(String number, String countryIso, ContactInfo contactInfo) {
125494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso);
125594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mContactInfoCache.put(numberCountryIso, contactInfo);
125694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
125794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
125894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
125994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    public void addGroup(int cursorPosition, int size, boolean expanded) {
126094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        super.addGroup(cursorPosition, size, expanded);
126194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
126294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
12634dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    /**
12644dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * Stores the day group associated with a call in the call log.
12654dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *
12664dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @param rowId The row Id of the current call.
12674dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @param dayGroup The day group the call belongs in.
12684dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     */
12694dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    @Override
12704dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    public void setDayGroup(long rowId, int dayGroup) {
12714dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        if (!mDayGroups.containsKey(rowId)) {
12724dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            mDayGroups.put(rowId, dayGroup);
12734dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        }
12744dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    }
12754dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn
12764dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    /**
12774dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * Clears the day group associations on re-bind of the call log.
12784dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     */
12794dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    @Override
12804dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    public void clearDayGroups() {
12814dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        mDayGroups.clear();
12824dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    }
12834dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn
128494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /*
128594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Get the number from the Contacts, if available, since sometimes
128694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * the number provided by caller id may not be formatted properly
128794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * depending on the carrier (roaming) in use at the time of the
128894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * incoming call.
128994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Logic : If the caller-id number starts with a "+", use it
129094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     *         Else if the number in the contacts starts with a "+", use that one
129194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     *         Else if the number in the contacts is longer, use that one
129294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
129394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    public String getBetterNumberFromContacts(String number, String countryIso) {
129494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        String matchingNumber = null;
129594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Look in the cache first. If it's not found then query the Phones db
129694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso);
129794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        ContactInfo ci = mContactInfoCache.getPossiblyExpired(numberCountryIso);
129894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (ci != null && ci != ContactInfo.EMPTY) {
129994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            matchingNumber = ci.number;
130094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        } else {
130194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            try {
130294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                Cursor phonesCursor = mContext.getContentResolver().query(
130394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number),
130494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        PhoneQuery._PROJECTION, null, null, null);
130594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                if (phonesCursor != null) {
1306ede67ec7813fb2c6fcda485adf82f11b55e3562cJay Shrauner                    try {
1307ede67ec7813fb2c6fcda485adf82f11b55e3562cJay Shrauner                        if (phonesCursor.moveToFirst()) {
1308ede67ec7813fb2c6fcda485adf82f11b55e3562cJay Shrauner                            matchingNumber = phonesCursor.getString(PhoneQuery.MATCHED_NUMBER);
1309ede67ec7813fb2c6fcda485adf82f11b55e3562cJay Shrauner                        }
1310ede67ec7813fb2c6fcda485adf82f11b55e3562cJay Shrauner                    } finally {
1311ede67ec7813fb2c6fcda485adf82f11b55e3562cJay Shrauner                        phonesCursor.close();
131294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    }
131394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                }
131494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            } catch (Exception e) {
131594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // Use the number from the call log
131694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
131794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
131894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (!TextUtils.isEmpty(matchingNumber) &&
131994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                (matchingNumber.startsWith("+")
132094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        || matchingNumber.length() > number.length())) {
132194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            number = matchingNumber;
132294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
132394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        return number;
132494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
1325146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
1326146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /**
1327146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * Retrieves the call Ids represented by the current call log row.
1328146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     *
1329146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * @param cursor Call log cursor to retrieve call Ids from.
1330146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * @param groupSize Number of calls associated with the current call log row.
1331146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * @return Array of call Ids.
1332146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     */
1333cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn    private long[] getCallIds(final Cursor cursor, final int groupSize) {
1334146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // We want to restore the position in the cursor at the end.
1335146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        int startingPosition = cursor.getPosition();
1336146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        long[] ids = new long[groupSize];
1337146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // Copy the ids of the rows in the group.
1338146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        for (int index = 0; index < groupSize; ++index) {
1339146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            ids[index] = cursor.getLong(CallLogQuery.ID);
1340146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            cursor.moveToNext();
1341146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
1342146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        cursor.moveToPosition(startingPosition);
1343146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        return ids;
1344146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    }
1345146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
1346146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /**
13474dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * Determines the description for a day group.
13484dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *
13494dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @param group The day group to retrieve the description for.
13504dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @return The day group description.
13514dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     */
13524dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    private CharSequence getGroupDescription(int group) {
13534dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn       if (group == CallLogGroupBuilder.DAY_GROUP_TODAY) {
13541e273313ff938ba0c7294dade433736d3fc5876bTyler Gunn           return mContext.getResources().getString(R.string.call_log_header_today);
13554dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn       } else if (group == CallLogGroupBuilder.DAY_GROUP_YESTERDAY) {
13561e273313ff938ba0c7294dade433736d3fc5876bTyler Gunn           return mContext.getResources().getString(R.string.call_log_header_yesterday);
13574dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn       } else {
13584dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn           return mContext.getResources().getString(R.string.call_log_header_other);
13594dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn       }
13604dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    }
13619686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati
13629686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati    public void onBadDataReported(String number) {
13639686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati        mContactInfoCache.expireAll();
13649686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati        mReportedToast.show();
13659686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati    }
1366b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee
1367b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee    /**
1368b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee     * Manages the state changes for the UI interaction where a call log row is expanded.
1369b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee     *
1370b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee     * @param view The view that was tapped
1371b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee     * @param animate Whether or not to animate the expansion/collapse
1372b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee     * @param forceExpand Whether or not to force the call log row into an expanded state regardless
1373b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee     *        of its previous state
1374b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee     */
1375b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee    private void handleRowExpanded(CallLogListItemView view, boolean animate, boolean forceExpand) {
1376b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee        final CallLogListItemViews views = (CallLogListItemViews) view.getTag();
1377b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee
1378b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee        if (forceExpand && isExpanded(views.rowId)) {
1379b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee            return;
1380b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee        }
1381b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee
1382b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee        // Hide or show the actions view.
1383b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee        boolean expanded = toggleExpansion(views.rowId);
1384b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee
1385b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee        // Trigger loading of the viewstub and visual expand or collapse.
1386b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee        expandOrCollapseActions(view, expanded);
1387b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee
1388b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee        // Animate the expansion or collapse.
1389b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee        if (mCallItemExpandedListener != null) {
1390b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee            if (animate) {
1391b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee                mCallItemExpandedListener.onItemExpanded(view);
1392b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee            }
1393b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee
1394b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee            // Animate the collapse of the previous item if it is still visible on screen.
1395b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee            if (mPreviouslyExpanded != NONE_EXPANDED) {
1396b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee                CallLogListItemView previousItem = mCallItemExpandedListener.getViewForCallId(
1397b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee                        mPreviouslyExpanded);
1398b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee
1399b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee                if (previousItem != null) {
1400b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee                    expandOrCollapseActions(previousItem, false);
1401b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee                    if (animate) {
1402b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee                        mCallItemExpandedListener.onItemExpanded(previousItem);
1403b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee                    }
1404b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee                }
1405b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee                mPreviouslyExpanded = NONE_EXPANDED;
1406b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee            }
1407b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee        }
1408b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee    }
140994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng}
1410