CallLogAdapter.java revision 8f7c4368817a17727b2132d399d0895e33f67a95
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
19b2eebafbc1f1e26b5178b2858ca335467b4bc341Nancy Chenimport android.content.ComponentName;
2094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.content.ContentValues;
2194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.content.Context;
22c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Chengimport android.content.Intent;
2394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.content.res.Resources;
2494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.database.Cursor;
2587ba489564b25d4a64c9faaeafea46e2f72d8933Nancy Chenimport android.graphics.drawable.Drawable;
2694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.net.Uri;
2794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.os.Handler;
2894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.os.Message;
2994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.provider.CallLog.Calls;
3094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.provider.ContactsContract.PhoneLookup;
31c329bfb6d47f20237d22e13297d5bbb72e612919Evan Charltonimport android.telecomm.PhoneAccountHandle;
329134e25d7ab8eb687a36ce7ba199e66f44550fddIhab Awadimport android.telecomm.TelecommManager;
3394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.text.TextUtils;
3494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.view.LayoutInflater;
3594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.view.View;
3694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.view.ViewGroup;
37c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Chengimport android.view.ViewStub;
3894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.view.ViewTreeObserver;
39c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Chengimport android.widget.ImageView;
40c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Chengimport android.widget.TextView;
41b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapatiimport android.widget.Toast;
4294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
4394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport com.android.common.widget.GroupingListAdapter;
4435071c06d1587942f5a66c8f12e6247e8f904d26Chiao Chengimport com.android.contacts.common.ContactPhotoManager;
4556cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Leeimport com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
4635071c06d1587942f5a66c8f12e6247e8f904d26Chiao Chengimport com.android.contacts.common.util.UriUtils;
4794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport com.android.dialer.PhoneCallDetails;
4894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport com.android.dialer.PhoneCallDetailsHelper;
499554500572ba82fbd7adb0a1637206ef870ef09eChiao Chengimport com.android.dialer.R;
507d20f8273886411ffc864231d59f780e450de3dbYorke Leeimport com.android.dialer.util.DialerUtils;
5194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport com.android.dialer.util.ExpirableCache;
5256cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee
5394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport com.google.common.annotations.VisibleForTesting;
5494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport com.google.common.base.Objects;
5594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
56146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunnimport java.util.HashMap;
5794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport java.util.LinkedList;
5894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
5994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng/**
6094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * Adapter class to fill in data for the Call Log.
6194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng */
62fb585079cc4c522c27f6dd6bf03fd296535960f3Yorke Leepublic class CallLogAdapter extends GroupingListAdapter
6394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        implements ViewTreeObserver.OnPreDrawListener, CallLogGroupBuilder.GroupCreator {
64c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
65146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /** The enumeration of {@link android.os.AsyncTask} objects used in this class. */
66146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    public enum Tasks {
67146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        REMOVE_CALL_LOG_ENTRIES,
68146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    }
69146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
70654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee    /** Interface used to inform a parent UI element that a list item has been expanded. */
71654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee    public interface CallItemExpandedListener {
72654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee        /**
73654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee         * @param view The {@link CallLogListItemView} that represents the item that was clicked
74654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee         *         on.
75654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee         */
76654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee        public void onItemExpanded(CallLogListItemView view);
778ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn
788ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn        /**
7968e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn         * Retrieves the call log view for the specified call Id.  If the view is not currently
8068e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn         * visible, returns null.
818ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn         *
8268e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn         * @param callId The call Id.
8368e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn         * @return The call log view.
848ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn         */
8568e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn        public CallLogListItemView getViewForCallId(long callId);
86654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee    }
87654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee
8894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Interface used to initiate a refresh of the content. */
8994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    public interface CallFetcher {
9094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public void fetchCalls();
9194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
9294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
939686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati    /** Implements onClickListener for the report button. */
949686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati    public interface OnReportButtonClickListener {
959686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati        public void onReportButtonClick(String number);
969686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati    }
979686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati
9894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
9994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Stores a phone number of a call with the country code where it originally occurred.
10094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
10194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Note the country does not necessarily specifies the country of the phone number itself, but
10294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * it is the country in which the user was in when the call was placed or received.
10394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
10494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private static final class NumberWithCountryIso {
10594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public final String number;
10694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public final String countryIso;
10794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
10894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public NumberWithCountryIso(String number, String countryIso) {
10994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            this.number = number;
11094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            this.countryIso = countryIso;
11194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
11294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
11394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        @Override
11494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public boolean equals(Object o) {
11594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (o == null) return false;
11694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!(o instanceof NumberWithCountryIso)) return false;
11794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            NumberWithCountryIso other = (NumberWithCountryIso) o;
11894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            return TextUtils.equals(number, other.number)
11994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    && TextUtils.equals(countryIso, other.countryIso);
12094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
12194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
12294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        @Override
12394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public int hashCode() {
12494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            return (number == null ? 0 : number.hashCode())
12594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    ^ (countryIso == null ? 0 : countryIso.hashCode());
12694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
12794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
12894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
12994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** The time in millis to delay starting the thread processing requests. */
13094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private static final int START_PROCESSING_REQUESTS_DELAY_MILLIS = 1000;
13194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
13294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** The size of the cache of contact info. */
13394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private static final int CONTACT_INFO_CACHE_SIZE = 100;
13494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
1358ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn    /** Constant used to indicate no row is expanded. */
1368ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn    private static final long NONE_EXPANDED = -1;
1378ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn
138704acc087ce359295475a46695c2821c55778344Chiao Cheng    protected final Context mContext;
13994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private final ContactInfoHelper mContactInfoHelper;
14094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private final CallFetcher mCallFetcher;
141b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati    private final Toast mReportedToast;
1429686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati    private final OnReportButtonClickListener mOnReportButtonClickListener;
14394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private ViewTreeObserver mViewTreeObserver = null;
14494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
14594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
14694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * A cache of the contact details for the phone numbers in the call log.
14794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
14894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * The content of the cache is expired (but not purged) whenever the application comes to
14994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * the foreground.
15094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
15194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * The key is number with the country in which the call was placed or received.
15294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
15394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private ExpirableCache<NumberWithCountryIso, ContactInfo> mContactInfoCache;
15494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
1558ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn    /**
1568ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     * Tracks the call log row which was previously expanded.  Used so that the closure of a
1578ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     * previously expanded call log entry can be animated on rebind.
1588ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     */
1598ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn    private long mPreviouslyExpanded = NONE_EXPANDED;
1608ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn
1618ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn    /**
1628ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     * Tracks the currently expanded call log row.
1638ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     */
1648ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn    private long mCurrentlyExpanded = NONE_EXPANDED;
165146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
16694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
1674dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  Hashmap, keyed by call Id, used to track the day group for a call.  As call log entries are
1684dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  put into the primary call groups in {@link com.android.dialer.calllog.CallLogGroupBuilder},
1694dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  they are also assigned a secondary "day group".  This hashmap tracks the day group assigned
1704dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  to all calls in the call log.  This information is used to trigger the display of a day
1714dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  group header above the call log entry at the start of a day group.
1724dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  Note: Multiple calls are grouped into a single primary "call group" in the call log, and
1734dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  the cursor used to bind rows includes all of these calls.  When determining if a day group
1744dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  change has occurred it is necessary to look at the last entry in the call log to determine
1754dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  its day group.  This hashmap provides a means of determining the previous day group without
1764dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  having to reverse the cursor to the start of the previous day call log entry.
1774dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     */
1784dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    private HashMap<Long,Integer> mDayGroups = new HashMap<Long, Integer>();
1794dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn
1804dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    /**
18194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * A request for contact details for the given number.
18294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
18394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private static final class ContactInfoRequest {
18494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        /** The number to look-up. */
18594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public final String number;
18694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        /** The country in which a call to or from this number was placed or received. */
18794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public final String countryIso;
18894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        /** The cached contact information stored in the call log. */
18994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public final ContactInfo callLogInfo;
19094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
19194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public ContactInfoRequest(String number, String countryIso, ContactInfo callLogInfo) {
19294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            this.number = number;
19394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            this.countryIso = countryIso;
19494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            this.callLogInfo = callLogInfo;
19594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
19694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
19794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        @Override
19894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public boolean equals(Object obj) {
19994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (this == obj) return true;
20094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (obj == null) return false;
20194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!(obj instanceof ContactInfoRequest)) return false;
20294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
20394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            ContactInfoRequest other = (ContactInfoRequest) obj;
20494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
20594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!TextUtils.equals(number, other.number)) return false;
20694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!TextUtils.equals(countryIso, other.countryIso)) return false;
20794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!Objects.equal(callLogInfo, other.callLogInfo)) return false;
20894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
20994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            return true;
21094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
21194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
21294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        @Override
21394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public int hashCode() {
21494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            final int prime = 31;
21594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            int result = 1;
21694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            result = prime * result + ((callLogInfo == null) ? 0 : callLogInfo.hashCode());
21794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            result = prime * result + ((countryIso == null) ? 0 : countryIso.hashCode());
21894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            result = prime * result + ((number == null) ? 0 : number.hashCode());
21994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            return result;
22094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
22194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
22294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
22394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
22494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * List of requests to update contact details.
22594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
22694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Each request is made of a phone number to look up, and the contact info currently stored in
22794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * the call log for this number.
22894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
22994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * The requests are added when displaying the contacts and are processed by a background
23094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * thread.
23194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
23294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private final LinkedList<ContactInfoRequest> mRequests;
23394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
23494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private boolean mLoading = true;
23594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private static final int REDRAW = 1;
23694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private static final int START_THREAD = 2;
23794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
23894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private QueryThread mCallerIdThread;
23994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
24094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Instance of helper class for managing views. */
24194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private final CallLogListItemHelper mCallLogViewsHelper;
24294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
24394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Helper to set up contact photos. */
24494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private final ContactPhotoManager mContactPhotoManager;
24594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Helper to parse and process phone numbers. */
24624ec319f8d410be8a1923c4033f927165876cbabYorke Lee    private PhoneNumberDisplayHelper mPhoneNumberHelper;
24794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Helper to group call log entries. */
24894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private final CallLogGroupBuilder mCallLogGroupBuilder;
24994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
250654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee    private CallItemExpandedListener mCallItemExpandedListener;
251654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee
25294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Can be set to true by tests to disable processing of requests. */
25394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private volatile boolean mRequestProcessingDisabled = false;
25494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
255c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    private boolean mIsCallLog = true;
256c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    private int mNumMissedCalls = 0;
257c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    private int mNumMissedCallsShown = 0;
258c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
259c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    private View mBadgeContainer;
260c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    private ImageView mBadgeImageView;
261c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    private TextView mBadgeText;
262c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
263b2687dd09eef2fc1aaf31ea4a3edf523677108a8Andrew Lee    private int mCallLogBackgroundColor;
264b2687dd09eef2fc1aaf31ea4a3edf523677108a8Andrew Lee    private int mExpandedBackgroundColor;
265b2687dd09eef2fc1aaf31ea4a3edf523677108a8Andrew Lee    private float mExpandedTranslationZ;
266b2687dd09eef2fc1aaf31ea4a3edf523677108a8Andrew Lee
267643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng    /** Listener for the primary or secondary actions in the list.
268643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng     *  Primary opens the call details.
269643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng     *  Secondary calls or plays.
270643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng     **/
271643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng    private final View.OnClickListener mActionListener = new View.OnClickListener() {
27294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        @Override
27394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public void onClick(View view) {
274643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng            startActivityForAction(view);
27594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
27694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    };
277643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng
278146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /**
279146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * The onClickListener used to expand or collapse the action buttons section for a call log
280146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * entry.
281146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     */
282146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    private final View.OnClickListener mExpandCollapseListener = new View.OnClickListener() {
283146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        @Override
284146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        public void onClick(View v) {
285654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee            final CallLogListItemView callLogItem = (CallLogListItemView) v.getParent().getParent();
2867be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn            final CallLogListItemViews views = (CallLogListItemViews) callLogItem.getTag();
2877be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn
2887be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn            // Hide or show the actions view.
2897be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn            boolean expanded = toggleExpansion(views.rowId);
2907be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn
2917be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn            // Trigger loading of the viewstub and visual expand or collapse.
2927be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn            expandOrCollapseActions(callLogItem, expanded);
293654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee
2948ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            // Animate the expansion or collapse.
295654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee            if (mCallItemExpandedListener != null) {
296654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee                mCallItemExpandedListener.onItemExpanded(callLogItem);
297654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee
29868e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn                // Animate the collapse of the previous item if it is still visible on screen.
29968e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn                if (mPreviouslyExpanded != NONE_EXPANDED) {
30068e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn                    CallLogListItemView previousItem = mCallItemExpandedListener.getViewForCallId(
30168e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn                            mPreviouslyExpanded);
30268e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn
30368e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn                    if (previousItem != null) {
30468e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn                        expandOrCollapseActions(previousItem, false);
30568e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn                        mCallItemExpandedListener.onItemExpanded(previousItem);
30668e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn                    }
30768e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn                    mPreviouslyExpanded = NONE_EXPANDED;
30868e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn                }
30968e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn            }
310146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
311146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    };
312146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
313643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng    private void startActivityForAction(View view) {
314643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng        final IntentProvider intentProvider = (IntentProvider) view.getTag();
315643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng        if (intentProvider != null) {
316643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng            final Intent intent = intentProvider.getIntent(mContext);
317643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng            // See IntentProvider.getCallDetailIntentProvider() for why this may be null.
318643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng            if (intent != null) {
3197d20f8273886411ffc864231d59f780e450de3dbYorke Lee                DialerUtils.startActivityWithErrorToast(mContext, intent);
32094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
32194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
322643e78532e5d40ca62e6545855f847e26eaffa4eChiao Cheng    }
32394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
32494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
32594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    public boolean onPreDraw() {
32694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // We only wanted to listen for the first draw (and this is it).
32794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        unregisterPreDrawListener();
32894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
32994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Only schedule a thread-creation message if the thread hasn't been
33094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // created yet. This is purely an optimization, to queue fewer messages.
33194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (mCallerIdThread == null) {
33294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mHandler.sendEmptyMessageDelayed(START_THREAD, START_PROCESSING_REQUESTS_DELAY_MILLIS);
33394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
33494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
33594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        return true;
33694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
33794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
33894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private Handler mHandler = new Handler() {
33994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        @Override
34094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public void handleMessage(Message msg) {
34194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            switch (msg.what) {
34294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                case REDRAW:
34394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    notifyDataSetChanged();
34494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    break;
34594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                case START_THREAD:
34694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    startRequestProcessing();
34794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    break;
34894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
34994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
35094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    };
35194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
352fb585079cc4c522c27f6dd6bf03fd296535960f3Yorke Lee    public CallLogAdapter(Context context, CallFetcher callFetcher,
353654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee            ContactInfoHelper contactInfoHelper, CallItemExpandedListener callItemExpandedListener,
3549686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati            OnReportButtonClickListener onReportButtonClickListener, boolean isCallLog) {
35594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        super(context);
35694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
35794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mContext = context;
35894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallFetcher = callFetcher;
35994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mContactInfoHelper = contactInfoHelper;
360c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        mIsCallLog = isCallLog;
361654df8fbbc7703c24aec687de902e2c72ba343ddYorke Lee        mCallItemExpandedListener = callItemExpandedListener;
36294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
3639686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati        mOnReportButtonClickListener = onReportButtonClickListener;
364b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati        mReportedToast = Toast.makeText(mContext, R.string.toast_caller_id_reported,
365b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati                Toast.LENGTH_SHORT);
366b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati
36794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mContactInfoCache = ExpirableCache.create(CONTACT_INFO_CACHE_SIZE);
36894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mRequests = new LinkedList<ContactInfoRequest>();
36994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
37094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        Resources resources = mContext.getResources();
37194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        CallTypeHelper callTypeHelper = new CallTypeHelper(resources);
372b2687dd09eef2fc1aaf31ea4a3edf523677108a8Andrew Lee        mCallLogBackgroundColor = resources.getColor(R.color.background_dialer_list_items);
373b2687dd09eef2fc1aaf31ea4a3edf523677108a8Andrew Lee        mExpandedBackgroundColor = resources.getColor(R.color.call_log_expanded_background_color);
374b2687dd09eef2fc1aaf31ea4a3edf523677108a8Andrew Lee        mExpandedTranslationZ = resources.getDimension(R.dimen.call_log_expanded_translation_z);
37594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
37694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mContactPhotoManager = ContactPhotoManager.getInstance(mContext);
37724ec319f8d410be8a1923c4033f927165876cbabYorke Lee        mPhoneNumberHelper = new PhoneNumberDisplayHelper(resources);
37894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        PhoneCallDetailsHelper phoneCallDetailsHelper = new PhoneCallDetailsHelper(
379fb0a934ad90f1855787563eb80f2c8fff7f640acChiao Cheng                resources, callTypeHelper, new PhoneNumberUtilsWrapper());
38094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallLogViewsHelper =
38194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                new CallLogListItemHelper(
38294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        phoneCallDetailsHelper, mPhoneNumberHelper, resources);
38394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallLogGroupBuilder = new CallLogGroupBuilder(this);
38494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
38594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
38694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
38794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Requery on background thread when {@link Cursor} changes.
38894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
38994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
39094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    protected void onContentChanged() {
39194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallFetcher.fetchCalls();
39294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
39394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
394fb585079cc4c522c27f6dd6bf03fd296535960f3Yorke Lee    public void setLoading(boolean loading) {
39594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mLoading = loading;
39694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
39794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
39894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
39994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    public boolean isEmpty() {
40094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (mLoading) {
40194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // We don't want the empty state to show when loading.
40294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            return false;
40394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        } else {
40494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            return super.isEmpty();
40594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
40694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
40794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
40894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
40994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Starts a background thread to process contact-lookup requests, unless one
41094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * has already been started.
41194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
41294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private synchronized void startRequestProcessing() {
41394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // For unit-testing.
41494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (mRequestProcessingDisabled) return;
41594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
41694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Idempotence... if a thread is already started, don't start another.
41794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (mCallerIdThread != null) return;
41894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
41994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallerIdThread = new QueryThread();
42094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallerIdThread.setPriority(Thread.MIN_PRIORITY);
42194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallerIdThread.start();
42294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
42394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
42494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
42594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Stops the background thread that processes updates and cancels any
42694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * pending requests to start it.
42794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
42894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    public synchronized void stopRequestProcessing() {
42994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Remove any pending requests to start the processing thread.
43094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mHandler.removeMessages(START_THREAD);
43194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (mCallerIdThread != null) {
43294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // Stop the thread; we are finished with it.
43394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mCallerIdThread.stopProcessing();
43494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mCallerIdThread.interrupt();
43594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mCallerIdThread = null;
43694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
43794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
43894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
43994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
44094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Stop receiving onPreDraw() notifications.
44194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
44294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private void unregisterPreDrawListener() {
44394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (mViewTreeObserver != null && mViewTreeObserver.isAlive()) {
44494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mViewTreeObserver.removeOnPreDrawListener(this);
44594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
44694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mViewTreeObserver = null;
44794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
44894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
44994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    public void invalidateCache() {
45094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mContactInfoCache.expireAll();
45194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
45294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Restart the request-processing thread after the next draw.
45394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        stopRequestProcessing();
45494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        unregisterPreDrawListener();
45594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
45694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
45794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
45894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Enqueues a request to look up the contact details for the given phone number.
45994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
46094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * It also provides the current contact info stored in the call log for this number.
46194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
46294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * If the {@code immediate} parameter is true, it will start immediately the thread that looks
46394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * up the contact information (if it has not been already started). Otherwise, it will be
46494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * started with a delay. See {@link #START_PROCESSING_REQUESTS_DELAY_MILLIS}.
46594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
466f73d2a97203261016e6c3f35ab8ab3a4a4f4c0b7Chiao Cheng    protected void enqueueRequest(String number, String countryIso, ContactInfo callLogInfo,
46794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            boolean immediate) {
46894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        ContactInfoRequest request = new ContactInfoRequest(number, countryIso, callLogInfo);
46994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        synchronized (mRequests) {
47094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!mRequests.contains(request)) {
47194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                mRequests.add(request);
47294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                mRequests.notifyAll();
47394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
47494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
47594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (immediate) startRequestProcessing();
47694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
47794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
47894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
47994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Queries the appropriate content provider for the contact associated with the number.
48094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
48194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Upon completion it also updates the cache in the call log, if it is different from
48294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * {@code callLogInfo}.
48394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
48494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * The number might be either a SIP address or a phone number.
48594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
48694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * It returns true if it updated the content of the cache and we should therefore tell the
48794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * view to update its content.
48894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
48994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private boolean queryContactInfo(String number, String countryIso, ContactInfo callLogInfo) {
49094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final ContactInfo info = mContactInfoHelper.lookupNumber(number, countryIso);
49194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
49294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (info == null) {
49394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // The lookup failed, just return without requesting to update the view.
49494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            return false;
49594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
49694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
49794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Check the existing entry in the cache: only if it has changed we should update the
49894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // view.
49994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso);
50094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        ContactInfo existingInfo = mContactInfoCache.getPossiblyExpired(numberCountryIso);
501034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee
502934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee        final boolean isRemoteSource = info.sourceType != 0;
503934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee
504934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee        // Don't force redraw if existing info in the cache is equal to {@link ContactInfo#EMPTY}
505934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee        // to avoid updating the data set for every new row that is scrolled into view.
506934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee        // see (https://googleplex-android-review.git.corp.google.com/#/c/166680/)
507934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee
508934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee        // Exception: Photo uris for contacts from remote sources are not cached in the call log
509934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee        // cache, so we have to force a redraw for these contacts regardless.
510934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee        boolean updated = (existingInfo != ContactInfo.EMPTY || isRemoteSource) &&
511934d3ee3052cfdd994e31ab2bcf00747fd9776d8Yorke Lee                !info.equals(existingInfo);
51294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
51394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Store the data in the cache so that the UI thread can use to display it. Store it
51494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // even if it has not changed so that it is marked as not expired.
51594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mContactInfoCache.put(numberCountryIso, info);
51694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Update the call log even if the cache it is up-to-date: it is possible that the cache
51794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // contains the value from a different call log entry.
51894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        updateCallLogContactInfoCache(number, countryIso, info, callLogInfo);
51994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        return updated;
52094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
52194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
52294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /*
52394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Handles requests for contact name and number type.
52494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
52594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private class QueryThread extends Thread {
52694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        private volatile boolean mDone = false;
52794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
52894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public QueryThread() {
52994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            super("CallLogAdapter.QueryThread");
53094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
53194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
53294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public void stopProcessing() {
53394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mDone = true;
53494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
53594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
53694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        @Override
53794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public void run() {
53894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            boolean needRedraw = false;
53994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            while (true) {
54094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // Check if thread is finished, and if so return immediately.
54194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                if (mDone) return;
54294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
54394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // Obtain next request, if any is available.
54494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // Keep synchronized section small.
54594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                ContactInfoRequest req = null;
54694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                synchronized (mRequests) {
54794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    if (!mRequests.isEmpty()) {
54894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        req = mRequests.removeFirst();
54994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    }
55094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                }
55194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
55294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                if (req != null) {
55394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    // Process the request. If the lookup succeeds, schedule a
55494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    // redraw.
55594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    needRedraw |= queryContactInfo(req.number, req.countryIso, req.callLogInfo);
55694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                } else {
55794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    // Throttle redraw rate by only sending them when there are
55894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    // more requests.
55994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    if (needRedraw) {
56094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        needRedraw = false;
56194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        mHandler.sendEmptyMessage(REDRAW);
56294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    }
56394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
56494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    // Wait until another request is available, or until this
56594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    // thread is no longer needed (as indicated by being
56694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    // interrupted).
56794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    try {
56894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        synchronized (mRequests) {
56994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                            mRequests.wait(1000);
57094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        }
57194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    } catch (InterruptedException ie) {
57294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        // Ignore, and attempt to continue processing requests.
57394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    }
57494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                }
57594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
57694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
57794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
57894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
57994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
58094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    protected void addGroups(Cursor cursor) {
58194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallLogGroupBuilder.addGroups(cursor);
58294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
58394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
58494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
58594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    protected View newStandAloneView(Context context, ViewGroup parent) {
586704acc087ce359295475a46695c2821c55778344Chiao Cheng        return newChildView(context, parent);
58794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
58894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
58994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
590704acc087ce359295475a46695c2821c55778344Chiao Cheng    protected View newGroupView(Context context, ViewGroup parent) {
591704acc087ce359295475a46695c2821c55778344Chiao Cheng        return newChildView(context, parent);
59294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
59394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
59494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
59594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    protected View newChildView(Context context, ViewGroup parent) {
596c329bfb6d47f20237d22e13297d5bbb72e612919Evan Charlton        LayoutInflater inflater = LayoutInflater.from(context);
59794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        View view = inflater.inflate(R.layout.call_log_list_item, parent, false);
598c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee
599c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee        // Get the views to bind to and cache them.
600c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee        CallLogListItemViews views = CallLogListItemViews.fromView(view);
601c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee        view.setTag(views);
602c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee
603c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee        // Set text height to false on the TextViews so they don't have extra padding.
604c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee        views.phoneCallDetailsViews.nameView.setElegantTextHeight(false);
605c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee        views.phoneCallDetailsViews.callLocationAndDate.setElegantTextHeight(false);
606c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee
60794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        return view;
60894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
60994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
61094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
611704acc087ce359295475a46695c2821c55778344Chiao Cheng    protected void bindStandAloneView(View view, Context context, Cursor cursor) {
61294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        bindView(view, cursor, 1);
61394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
61494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
61594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
616704acc087ce359295475a46695c2821c55778344Chiao Cheng    protected void bindChildView(View view, Context context, Cursor cursor) {
617704acc087ce359295475a46695c2821c55778344Chiao Cheng        bindView(view, cursor, 1);
61894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
61994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
62094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
62194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    protected void bindGroupView(View view, Context context, Cursor cursor, int groupSize,
62294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            boolean expanded) {
62394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        bindView(view, cursor, groupSize);
62494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
62594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
62694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private void findAndCacheViews(View view) {
62794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
62894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
62994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
63094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Binds the views in the entry to the data in the call log.
63194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     *
63294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * @param view the view corresponding to this entry
63394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * @param c the cursor pointing to the entry in the call log
63494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * @param count the number of entries in the current item, greater than 1 if it is a group
63594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
63694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private void bindView(View view, Cursor c, int count) {
6378ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn        final CallLogListItemView callLogItemView = (CallLogListItemView) view;
63894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final CallLogListItemViews views = (CallLogListItemViews) view.getTag();
639f517e7bb367d1ed749b500959d0a0a1ba8c3d5e5Christine Chen
64094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Default case: an item in the call log.
64194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        views.primaryActionView.setVisibility(View.VISIBLE);
64294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
64394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final String number = c.getString(CallLogQuery.NUMBER);
644719a7adde25e0a717816b00668c16c3a1e3c5518Jay Shrauner        final int numberPresentation = c.getInt(CallLogQuery.NUMBER_PRESENTATION);
64594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final long date = c.getLong(CallLogQuery.DATE);
64694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final long duration = c.getLong(CallLogQuery.DURATION);
64794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final int callType = c.getInt(CallLogQuery.CALL_TYPE);
648b2eebafbc1f1e26b5178b2858ca335467b4bc341Nancy Chen        final PhoneAccountHandle accountHandle = PhoneAccountUtils.getAccount(
649b2eebafbc1f1e26b5178b2858ca335467b4bc341Nancy Chen                c.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME),
650b2eebafbc1f1e26b5178b2858ca335467b4bc341Nancy Chen                c.getString(CallLogQuery.ACCOUNT_ID));
651b2eebafbc1f1e26b5178b2858ca335467b4bc341Nancy Chen        final Drawable accountIcon = PhoneAccountUtils.getAccountIcon(mContext,
652b2eebafbc1f1e26b5178b2858ca335467b4bc341Nancy Chen                accountHandle);
65394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final String countryIso = c.getString(CallLogQuery.COUNTRY_ISO);
6548cd9423bd04584acbcbf178bf6a1c1953debb8daYorke Lee
655146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        final long rowId = c.getLong(CallLogQuery.ID);
656146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        views.rowId = rowId;
657146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
6584dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        // For entries in the call log, check if the day group has changed and display a header
6594dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        // if necessary.
6604dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        if (mIsCallLog) {
6614dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            int currentGroup = getDayGroupForCall(rowId);
6624dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            int previousGroup = getPreviousDayGroup(c);
6634dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            if (currentGroup != previousGroup) {
6644dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn                views.dayGroupHeader.setVisibility(View.VISIBLE);
6654dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn                views.dayGroupHeader.setText(getGroupDescription(currentGroup));
6664dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            } else {
6674dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn                views.dayGroupHeader.setVisibility(View.GONE);
6684dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            }
6694dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        } else {
6704dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            views.dayGroupHeader.setVisibility(View.GONE);
6714dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        }
6724dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn
673146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // Store some values used when the actions ViewStub is inflated on expansion of the actions
674146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // section.
675146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        views.number = number;
676146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        views.numberPresentation = numberPresentation;
677146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        views.callType = callType;
6788f7c4368817a17727b2132d399d0895e33f67a95Nancy Chen        // NOTE: This is currently not being used, but can be used in future versions.
6798f7c4368817a17727b2132d399d0895e33f67a95Nancy Chen        views.accountHandle = accountHandle;
680146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        views.voicemailUri = c.getString(CallLogQuery.VOICEMAIL_URI);
681146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // Stash away the Ids of the calls so that we can support deleting a row in the call log.
682cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn        views.callIds = getCallIds(c, count);
68394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
68494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final ContactInfo cachedContactInfo = getContactInfoFromCallLog(c);
68594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
68656cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        final boolean isVoicemailNumber =
68756cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee                PhoneNumberUtilsWrapper.INSTANCE.isVoicemailNumber(number);
68856cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee
689146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // Where binding and not in the call log, use default behaviour of invoking a call when
690146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // tapping the primary view.
691146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        if (!mIsCallLog) {
692146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.primaryActionView.setOnClickListener(this.mActionListener);
693fb585079cc4c522c27f6dd6bf03fd296535960f3Yorke Lee
694146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            // Set return call intent, otherwise null.
695146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            if (PhoneNumberUtilsWrapper.canPlaceCallsTo(number, numberPresentation)) {
696146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn                // Sets the primary action to call the number.
6978f7c4368817a17727b2132d399d0895e33f67a95Nancy Chen                views.primaryActionView.setTag(IntentProvider.getReturnCallIntentProvider(number));
69845ed3b5932ed590b45235d7b2befa736a95e7f75Tyler Gunn            } else {
699146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn                // Number is not callable, so hide button.
700146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn                views.primaryActionView.setTag(null);
70145ed3b5932ed590b45235d7b2befa736a95e7f75Tyler Gunn            }
70294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        } else {
703146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            // In the call log, expand/collapse an actions section for the call log entry when
704146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            // the primary view is tapped.
705146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.primaryActionView.setOnClickListener(this.mExpandCollapseListener);
706146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
707146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            // Note: Binding of the action buttons is done as required in configureActionViews
708146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            // when the user expands the actions ViewStub.
709146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
710146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
71194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Lookup contacts with this number
71294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso);
71394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        ExpirableCache.CachedValue<ContactInfo> cachedInfo =
71494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                mContactInfoCache.getCachedValue(numberCountryIso);
71594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        ContactInfo info = cachedInfo == null ? null : cachedInfo.getValue();
716fb0a934ad90f1855787563eb80f2c8fff7f640acChiao Cheng        if (!PhoneNumberUtilsWrapper.canPlaceCallsTo(number, numberPresentation)
71756cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee                || isVoicemailNumber) {
71894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // If this is a number that cannot be dialed, there is no point in looking up a contact
71994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // for it.
72094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            info = ContactInfo.EMPTY;
72194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        } else if (cachedInfo == null) {
72294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mContactInfoCache.put(numberCountryIso, ContactInfo.EMPTY);
72394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // Use the cached contact info from the call log.
72494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            info = cachedContactInfo;
72594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // The db request should happen on a non-UI thread.
72694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // Request the contact details immediately since they are currently missing.
72794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            enqueueRequest(number, countryIso, cachedContactInfo, true);
72894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // We will format the phone number when we make the background request.
72994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        } else {
73094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (cachedInfo.isExpired()) {
73194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // The contact info is no longer up to date, we should request it. However, we
73294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // do not need to request them immediately.
73394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                enqueueRequest(number, countryIso, cachedContactInfo, false);
73494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            } else  if (!callLogInfoMatches(cachedContactInfo, info)) {
73594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // The call log information does not match the one we have, look it up again.
73694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // We could simply update the call log directly, but that needs to be done in a
73794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // background thread, so it is easier to simply request a new lookup, which will, as
73894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // a side-effect, update the call log.
73994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                enqueueRequest(number, countryIso, cachedContactInfo, false);
74094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
74194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
74294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (info == ContactInfo.EMPTY) {
74394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // Use the cached contact info from the call log.
74494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                info = cachedContactInfo;
74594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
74694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
74794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
74894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final Uri lookupUri = info.lookupUri;
74994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final String name = info.name;
75094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final int ntype = info.type;
75194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final String label = info.label;
75294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final long photoId = info.photoId;
753034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee        final Uri photoUri = info.photoUri;
75494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        CharSequence formattedNumber = info.formattedNumber;
75594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final int[] callTypes = getCallTypes(c, count);
75694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final String geocode = c.getString(CallLogQuery.GEOCODED_LOCATION);
75756cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        final int sourceType = info.sourceType;
7588b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        final int features = getCallFeatures(c, count);
7598cd9423bd04584acbcbf178bf6a1c1953debb8daYorke Lee        final String transcription = c.getString(CallLogQuery.TRANSCRIPTION);
7608b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        Long dataUsage = null;
7618b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        if (!c.isNull(CallLogQuery.DATA_USAGE)) {
7628b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn            dataUsage = c.getLong(CallLogQuery.DATA_USAGE);
7638b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        }
7648b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn
76594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final PhoneCallDetails details;
766704acc087ce359295475a46695c2821c55778344Chiao Cheng
767b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati        views.reported = info.isBadData;
768b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati        views.isExternal = mContactInfoHelper.isExternal(info.sourceType);
769b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati
7709686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati        // Restore expansion state of the row on rebind.  Inflate the actions ViewStub if required,
7719686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati        // and set its visibility state accordingly.
7729686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati        expandOrCollapseActions(callLogItemView, isExpanded(rowId));
7739686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati
77494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (TextUtils.isEmpty(name)) {
775719a7adde25e0a717816b00668c16c3a1e3c5518Jay Shrauner            details = new PhoneCallDetails(number, numberPresentation,
776719a7adde25e0a717816b00668c16c3a1e3c5518Jay Shrauner                    formattedNumber, countryIso, geocode, callTypes, date,
7771970263aad3e26c0e36dbe3783bef5d9f0ff29f0Nancy Chen                    duration, null, accountIcon, features, dataUsage, transcription);
77894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        } else {
779719a7adde25e0a717816b00668c16c3a1e3c5518Jay Shrauner            details = new PhoneCallDetails(number, numberPresentation,
780719a7adde25e0a717816b00668c16c3a1e3c5518Jay Shrauner                    formattedNumber, countryIso, geocode, callTypes, date,
78187ba489564b25d4a64c9faaeafea46e2f72d8933Nancy Chen                    duration, name, ntype, label, lookupUri, photoUri, sourceType,
7821970263aad3e26c0e36dbe3783bef5d9f0ff29f0Nancy Chen                    null, accountIcon, features, dataUsage, transcription);
78394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
78494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
785d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn        mCallLogViewsHelper.setPhoneCallDetails(views, details);
786034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee
78756cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        int contactType = ContactPhotoManager.TYPE_DEFAULT;
78856cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee
78956cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        if (isVoicemailNumber) {
79056cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee            contactType = ContactPhotoManager.TYPE_VOICEMAIL;
79156cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        } else if (mContactInfoHelper.isBusiness(info.sourceType)) {
79256cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee            contactType = ContactPhotoManager.TYPE_BUSINESS;
79356cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        }
79456cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee
795a5804f5b62bd87a0c8a35d7651a6862ecc1f220bYorke Lee        String lookupKey = lookupUri == null ? null
796a5804f5b62bd87a0c8a35d7651a6862ecc1f220bYorke Lee                : ContactInfoHelper.getLookupKeyFromUri(lookupUri);
79756cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee
79856cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        String nameForDefaultImage = null;
79956cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        if (TextUtils.isEmpty(name)) {
80056cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee            nameForDefaultImage = mPhoneNumberHelper.getDisplayNumber(details.number,
80156cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee                    details.numberPresentation, details.formattedNumber).toString();
80256cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        } else {
80356cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee            nameForDefaultImage = name;
80456cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        }
80556cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee
806034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee        if (photoId == 0 && photoUri != null) {
80756cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee            setPhoto(views, photoUri, lookupUri, nameForDefaultImage, lookupKey, contactType);
808034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee        } else {
80956cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee            setPhoto(views, photoId, lookupUri, nameForDefaultImage, lookupKey, contactType);
810034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee        }
81194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
81294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Listen for the first draw
81394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (mViewTreeObserver == null) {
81494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mViewTreeObserver = view.getViewTreeObserver();
81594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mViewTreeObserver.addOnPreDrawListener(this);
81694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
817704acc087ce359295475a46695c2821c55778344Chiao Cheng
818c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        bindBadge(view, info, details, callType);
819c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    }
820c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
821146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /**
8224dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * Retrieves the day group of the previous call in the call log.  Used to determine if the day
8234dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * group has changed and to trigger display of the day group text.
8244dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *
8254dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @param cursor The call log cursor.
8264dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @return The previous day group, or DAY_GROUP_NONE if this is the first call.
8274dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     */
8284dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    private int getPreviousDayGroup(Cursor cursor) {
8294dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        // We want to restore the position in the cursor at the end.
8304dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        int startingPosition = cursor.getPosition();
8314dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        int dayGroup = CallLogGroupBuilder.DAY_GROUP_NONE;
8324dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        if (cursor.moveToPrevious()) {
8334dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            long previousRowId = cursor.getLong(CallLogQuery.ID);
8344dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            dayGroup = getDayGroupForCall(previousRowId);
8354dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        }
8364dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        cursor.moveToPosition(startingPosition);
8374dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        return dayGroup;
8384dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    }
8394dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn
8404dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    /**
8414dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * Given a call Id, look up the day group that the call belongs to.  The day group data is
8424dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * populated in {@link com.android.dialer.calllog.CallLogGroupBuilder}.
8434dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *
8444dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @param callId The call to retrieve the day group for.
8454dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @return The day group for the call.
8464dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     */
8474dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    private int getDayGroupForCall(long callId) {
8484dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        if (mDayGroups.containsKey(callId)) {
8494dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            return mDayGroups.get(callId);
8504dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        }
8514dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        return CallLogGroupBuilder.DAY_GROUP_NONE;
8524dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    }
8534dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    /**
8548ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     * Determines if a call log row with the given Id is expanded.
8558ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     * @param rowId The row Id of the call.
8568ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     * @return True if the row should be expanded.
857146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     */
858146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    private boolean isExpanded(long rowId) {
8598ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn        return mCurrentlyExpanded == rowId;
860146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    }
861146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
862146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /**
863146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * Toggles the expansion state tracked for the call log row identified by rowId and returns
8648ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     * the new expansion state.  Assumes that only a single call log row will be expanded at any
8658ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn     * one point and tracks the current and previous expanded item.
866146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     *
867146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * @param rowId The row Id associated with the call log row to expand/collapse.
868146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * @return True where the row is now expanded, false otherwise.
869146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     */
870146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    private boolean toggleExpansion(long rowId) {
8718ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn        if (rowId == mCurrentlyExpanded) {
8728ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            // Collapsing currently expanded row.
8738ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            mPreviouslyExpanded = NONE_EXPANDED;
8748ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            mCurrentlyExpanded = NONE_EXPANDED;
875146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
8768ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            return false;
8778ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn        } else {
8788ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            // Expanding a row (collapsing current expanded one).
8798ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn
88068e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn            mPreviouslyExpanded = mCurrentlyExpanded;
8818ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            mCurrentlyExpanded = rowId;
8828ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            return true;
8838ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn        }
884146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    }
885146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
886146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /**
8879138834059797469f73390c9faa71ce98b4434c1Tyler Gunn     * Expands or collapses the view containing the CALLBACK, VOICEMAIL and DETAILS action buttons.
888146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     *
889146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * @param callLogItem The call log entry parent view.
8907be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn     * @param isExpanded The new expansion state of the view.
891146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     */
8928ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn    private void expandOrCollapseActions(CallLogListItemView callLogItem, boolean isExpanded) {
893146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        final CallLogListItemViews views = (CallLogListItemViews)callLogItem.getTag();
894146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
8957be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn        if (isExpanded) {
8967be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn            // Inflate the view stub if necessary, and wire up the event handlers.
8977be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn            inflateActionViewStub(callLogItem);
898146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
899146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.actionsView.setVisibility(View.VISIBLE);
9008ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            views.actionsView.setAlpha(1.0f);
901b2687dd09eef2fc1aaf31ea4a3edf523677108a8Andrew Lee            views.callLogEntryView.setBackgroundColor(mExpandedBackgroundColor);
9020d8019cf7cb048e5da044559460e08c5284d8f48Chris Craik            views.callLogEntryView.setTranslationZ(mExpandedTranslationZ);
9030d8019cf7cb048e5da044559460e08c5284d8f48Chris Craik            callLogItem.setTranslationZ(mExpandedTranslationZ); // WAR
904146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
905146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            // Attempt to give accessibility focus to one of the action buttons.
906146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            // This ensures that a user realizes the expansion occurred.
907146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            // NOTE(tgunn): requestAccessibilityFocus returns true if the requested
908146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            // focus was successful.  The first successful focus will satisfy the OR
909146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            // block and block further attempts to set focus.
910146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            boolean focused = views.callBackButtonView.requestAccessibilityFocus() ||
9115619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn                    views.videoCallButtonView.requestAccessibilityFocus() ||
912146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn                    views.voicemailButtonView.requestAccessibilityFocus() ||
913cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn                    views.detailsButtonView.requestAccessibilityFocus();
914146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        } else {
9157be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn            // When recycling a view, it is possible the actionsView ViewStub was previously
9167be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn            // inflated so we should hide it in this case.
9178ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            if (views.actionsView != null) {
9187be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn                views.actionsView.setVisibility(View.GONE);
9197be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn            }
9207be92c925c842d45aa14f4bb7edc2f64f528b58bTyler Gunn
921b2687dd09eef2fc1aaf31ea4a3edf523677108a8Andrew Lee            views.callLogEntryView.setBackgroundColor(mCallLogBackgroundColor);
9220d8019cf7cb048e5da044559460e08c5284d8f48Chris Craik            views.callLogEntryView.setTranslationZ(0);
9230d8019cf7cb048e5da044559460e08c5284d8f48Chris Craik            callLogItem.setTranslationZ(0); // WAR
924146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
925146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    }
926146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
927146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /**
928146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * Configures the action buttons in the expandable actions ViewStub.  The ViewStub is not
929146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * inflated during initial binding, so click handlers, tags and accessibility text must be set
930146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * here, if necessary.
931146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     *
932146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * @param callLogItem The call log list item view.
933146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     */
934b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati    private void inflateActionViewStub(final View callLogItem) {
935146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        final CallLogListItemViews views = (CallLogListItemViews)callLogItem.getTag();
936146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
937146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        ViewStub stub = (ViewStub)callLogItem.findViewById(R.id.call_log_entry_actions_stub);
938146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        if (stub != null) {
939146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.actionsView = stub.inflate();
940146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
941146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
942146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        if (views.callBackButtonView == null) {
9438ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            views.callBackButtonView = (TextView)views.actionsView.findViewById(
9448ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn                    R.id.call_back_action);
945146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
946146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
9475619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn        if (views.videoCallButtonView == null) {
9485619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn            views.videoCallButtonView = (TextView)views.actionsView.findViewById(
9495619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn                    R.id.video_call_action);
9505619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn        }
9515619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn
952146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        if (views.voicemailButtonView == null) {
9538ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn            views.voicemailButtonView = (TextView)views.actionsView.findViewById(
9548ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn                    R.id.voicemail_action);
955146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
956146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
957cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn        if (views.detailsButtonView == null) {
958cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn            views.detailsButtonView = (TextView)views.actionsView.findViewById(R.id.details_action);
959cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn        }
960cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn
961b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati        if (views.reportButtonView == null) {
962b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati            views.reportButtonView = (TextView)views.actionsView.findViewById(R.id.report_action);
963b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati            views.reportButtonView.setOnClickListener(new View.OnClickListener() {
964b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati                @Override
965b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati                public void onClick(View v) {
9669686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati                    if (mOnReportButtonClickListener != null) {
9679686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati                        mOnReportButtonClickListener.onReportButtonClick(views.number);
9689686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati                    }
969b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati                }
970b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati            });
971b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati        }
972b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati
973146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        bindActionButtons(views);
974146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    }
975146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
976146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /***
9779138834059797469f73390c9faa71ce98b4434c1Tyler Gunn     * Binds click handlers and intents to the voicemail, details and callback action buttons.
978146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     *
979146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * @param views  The call log item views.
980146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     */
981146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    private void bindActionButtons(CallLogListItemViews views) {
9825619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn        boolean canPlaceCallToNumber =
9835619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn                PhoneNumberUtilsWrapper.canPlaceCallsTo(views.number, views.numberPresentation);
984146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // Set return call intent, otherwise null.
9855619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn        if (canPlaceCallToNumber) {
986146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            // Sets the primary action to call the number.
987146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.callBackButtonView.setTag(
9888f7c4368817a17727b2132d399d0895e33f67a95Nancy Chen                    IntentProvider.getReturnCallIntentProvider(views.number));
989146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.callBackButtonView.setVisibility(View.VISIBLE);
990146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.callBackButtonView.setOnClickListener(mActionListener);
991146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        } else {
992146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            // Number is not callable, so hide button.
993146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.callBackButtonView.setTag(null);
994146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.callBackButtonView.setVisibility(View.GONE);
995146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
996146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
9975619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn        // If one of the calls had video capabilities, show the video call button.
9985619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn        if (canPlaceCallToNumber && views.phoneCallDetailsViews.callTypeIcons.isVideoShown()) {
9995619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn            views.videoCallButtonView.setTag(
10008f7c4368817a17727b2132d399d0895e33f67a95Nancy Chen                    IntentProvider.getReturnVideoCallIntentProvider(views.number));
10015619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn            views.videoCallButtonView.setVisibility(View.VISIBLE);
10025619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn            views.videoCallButtonView.setOnClickListener(mActionListener);
10035619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn        } else {
10045619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn            views.videoCallButtonView.setTag(null);
10055619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn            views.videoCallButtonView.setVisibility(View.GONE);
10065619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn        }
10075619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn
1008146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // For voicemail calls, show the "VOICEMAIL" action button; hide otherwise.
1009146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        if (views.callType == Calls.VOICEMAIL_TYPE) {
1010146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.voicemailButtonView.setOnClickListener(mActionListener);
1011146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.voicemailButtonView.setTag(
1012146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn                    IntentProvider.getPlayVoicemailIntentProvider(
1013146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn                            views.rowId, views.voicemailUri));
1014146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.voicemailButtonView.setVisibility(View.VISIBLE);
1015cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn
1016cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn            views.detailsButtonView.setVisibility(View.GONE);
1017146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        } else {
1018146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.voicemailButtonView.setTag(null);
1019146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            views.voicemailButtonView.setVisibility(View.GONE);
1020cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn
1021cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn            views.detailsButtonView.setOnClickListener(mActionListener);
1022cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn            views.detailsButtonView.setTag(
1023cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn                    IntentProvider.getCallDetailIntentProvider(
1024cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn                            views.rowId, views.callIds, null)
1025cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn            );
10265619f2ed87cb207352c0ff5578348baeb69ee202Tyler Gunn
1027b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati            if (views.isExternal && !views.reported) {
1028b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati                views.reportButtonView.setVisibility(View.VISIBLE);
10299686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati            } else {
10309686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati                views.reportButtonView.setVisibility(View.GONE);
1031b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati            }
1032146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
1033146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
1034146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        mCallLogViewsHelper.setActionContentDescriptions(views);
1035146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    }
1036146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
1037c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    protected void bindBadge(View view, ContactInfo info, PhoneCallDetails details, int callType) {
1038c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
1039c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        // Do not show badge in call log.
1040c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        if (!mIsCallLog) {
1041c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            final int numMissed = getNumMissedCalls(callType);
1042c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            final ViewStub stub = (ViewStub) view.findViewById(R.id.link_stub);
10439fd02a6742c8e9139a03d80bacca360238be11bfChiao Cheng
1044c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            if (shouldShowBadge(numMissed, info, details)) {
10459fd02a6742c8e9139a03d80bacca360238be11bfChiao Cheng                // Do not process if the data has not changed (optimization since bind view is
10469fd02a6742c8e9139a03d80bacca360238be11bfChiao Cheng                // called multiple times due to contact lookup).
10479fd02a6742c8e9139a03d80bacca360238be11bfChiao Cheng                if (numMissed == mNumMissedCallsShown) {
10489fd02a6742c8e9139a03d80bacca360238be11bfChiao Cheng                    return;
10499fd02a6742c8e9139a03d80bacca360238be11bfChiao Cheng                }
1050c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
1051c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                // stub will be null if it was already inflated.
1052c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                if (stub != null) {
1053c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                    final View inflated = stub.inflate();
1054c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                    inflated.setVisibility(View.VISIBLE);
1055c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                    mBadgeContainer = inflated.findViewById(R.id.badge_link_container);
1056c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                    mBadgeImageView = (ImageView) inflated.findViewById(R.id.badge_image);
1057c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                    mBadgeText = (TextView) inflated.findViewById(R.id.badge_text);
1058c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                }
1059c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
1060c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                mBadgeContainer.setOnClickListener(getBadgeClickListener());
1061c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                mBadgeImageView.setImageResource(getBadgeImageResId());
1062c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                mBadgeText.setText(getBadgeText(numMissed));
1063c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
1064c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                mNumMissedCallsShown = numMissed;
1065c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            } else {
1066c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                // Hide badge if it was previously shown.
1067c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                if (stub == null) {
1068c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                    final View container = view.findViewById(R.id.badge_container);
1069c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                    if (container != null) {
1070c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                        container.setVisibility(View.GONE);
1071c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                    }
1072c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                }
1073c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            }
1074c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        }
1075c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    }
1076c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
1077c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    public void setMissedCalls(Cursor data) {
1078c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        final int missed;
1079c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        if (data == null) {
1080c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            missed = 0;
1081c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        } else {
1082c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            missed = data.getCount();
1083c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        }
1084c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        // Only need to update if the number of calls changed.
1085c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        if (missed != mNumMissedCalls) {
1086c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            mNumMissedCalls = missed;
1087c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            notifyDataSetChanged();
1088c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        }
1089c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    }
1090c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
1091c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    protected View.OnClickListener getBadgeClickListener() {
1092c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        return new View.OnClickListener() {
1093c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            @Override
1094c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            public void onClick(View v) {
1095c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                final Intent intent = new Intent(mContext, CallLogActivity.class);
1096c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng                mContext.startActivity(intent);
1097c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            }
1098c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        };
1099c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    }
1100c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
1101c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    /**
1102c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng     * Get the resource id for the image to be shown for the badge.
1103c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng     */
1104c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    protected int getBadgeImageResId() {
1105c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        return R.drawable.ic_call_log_blue;
1106c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    }
1107c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
1108c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    /**
1109c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng     * Get the text to be shown for the badge.
1110c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng     *
1111c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng     * @param numMissed The number of missed calls.
1112c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng     */
1113c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    protected String getBadgeText(int numMissed) {
1114c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        return mContext.getResources().getString(R.string.num_missed_calls, numMissed);
1115704acc087ce359295475a46695c2821c55778344Chiao Cheng    }
1116704acc087ce359295475a46695c2821c55778344Chiao Cheng
1117c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    /**
1118c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng     * Whether to show the badge.
1119c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng     *
1120c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng     * @param numMissedCalls The number of missed calls.
1121c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng     * @param info The contact info.
1122c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng     * @param details The call detail.
1123c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng     * @return {@literal true} if badge should be shown.  {@literal false} otherwise.
1124c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng     */
1125c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    protected boolean shouldShowBadge(int numMissedCalls, ContactInfo info,
1126e6933be00d2ecc266612a374a62e05352937408eChiao Cheng            PhoneCallDetails details) {
1127c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        return numMissedCalls > 0;
1128c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    }
1129c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
1130c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    private int getNumMissedCalls(int callType) {
1131c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        if (callType == Calls.MISSED_TYPE) {
1132c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            // Exclude the current missed call shown in the shortcut.
1133c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng            return mNumMissedCalls - 1;
1134c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        }
1135c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng        return mNumMissedCalls;
113694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
113794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
113894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Checks whether the contact info from the call log matches the one from the contacts db. */
113994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private boolean callLogInfoMatches(ContactInfo callLogInfo, ContactInfo info) {
114094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // The call log only contains a subset of the fields in the contacts db.
114194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Only check those.
114294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        return TextUtils.equals(callLogInfo.name, info.name)
114394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                && callLogInfo.type == info.type
114494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                && TextUtils.equals(callLogInfo.label, info.label);
114594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
114694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
114794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Stores the updated contact info in the call log if it is different from the current one. */
114894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private void updateCallLogContactInfoCache(String number, String countryIso,
114994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            ContactInfo updatedInfo, ContactInfo callLogInfo) {
115094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final ContentValues values = new ContentValues();
115194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        boolean needsUpdate = false;
115294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
115394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (callLogInfo != null) {
115494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!TextUtils.equals(updatedInfo.name, callLogInfo.name)) {
115594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                values.put(Calls.CACHED_NAME, updatedInfo.name);
115694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                needsUpdate = true;
115794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
115894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
115994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (updatedInfo.type != callLogInfo.type) {
116094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                values.put(Calls.CACHED_NUMBER_TYPE, updatedInfo.type);
116194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                needsUpdate = true;
116294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
116394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
116494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!TextUtils.equals(updatedInfo.label, callLogInfo.label)) {
116594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                values.put(Calls.CACHED_NUMBER_LABEL, updatedInfo.label);
116694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                needsUpdate = true;
116794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
116894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!UriUtils.areEqual(updatedInfo.lookupUri, callLogInfo.lookupUri)) {
116994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                values.put(Calls.CACHED_LOOKUP_URI, UriUtils.uriToString(updatedInfo.lookupUri));
117094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                needsUpdate = true;
117194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
1172746dba885dc50c9f723456b01cfc7dbfcc9a49b0Tyler Gunn            // Only replace the normalized number if the new updated normalized number isn't empty.
1173746dba885dc50c9f723456b01cfc7dbfcc9a49b0Tyler Gunn            if (!TextUtils.isEmpty(updatedInfo.normalizedNumber) &&
1174746dba885dc50c9f723456b01cfc7dbfcc9a49b0Tyler Gunn                    !TextUtils.equals(updatedInfo.normalizedNumber, callLogInfo.normalizedNumber)) {
117594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                values.put(Calls.CACHED_NORMALIZED_NUMBER, updatedInfo.normalizedNumber);
117694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                needsUpdate = true;
117794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
117894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!TextUtils.equals(updatedInfo.number, callLogInfo.number)) {
117994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                values.put(Calls.CACHED_MATCHED_NUMBER, updatedInfo.number);
118094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                needsUpdate = true;
118194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
118294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (updatedInfo.photoId != callLogInfo.photoId) {
118394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                values.put(Calls.CACHED_PHOTO_ID, updatedInfo.photoId);
118494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                needsUpdate = true;
118594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
118694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            if (!TextUtils.equals(updatedInfo.formattedNumber, callLogInfo.formattedNumber)) {
118794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                values.put(Calls.CACHED_FORMATTED_NUMBER, updatedInfo.formattedNumber);
118894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                needsUpdate = true;
118994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
119094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        } else {
119194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // No previous values, store all of them.
119294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            values.put(Calls.CACHED_NAME, updatedInfo.name);
119394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            values.put(Calls.CACHED_NUMBER_TYPE, updatedInfo.type);
119494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            values.put(Calls.CACHED_NUMBER_LABEL, updatedInfo.label);
119594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            values.put(Calls.CACHED_LOOKUP_URI, UriUtils.uriToString(updatedInfo.lookupUri));
119694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            values.put(Calls.CACHED_MATCHED_NUMBER, updatedInfo.number);
119794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            values.put(Calls.CACHED_NORMALIZED_NUMBER, updatedInfo.normalizedNumber);
119894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            values.put(Calls.CACHED_PHOTO_ID, updatedInfo.photoId);
119994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            values.put(Calls.CACHED_FORMATTED_NUMBER, updatedInfo.formattedNumber);
120094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            needsUpdate = true;
120194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
120294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
120394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (!needsUpdate) return;
120494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
120594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (countryIso == null) {
120694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mContext.getContentResolver().update(Calls.CONTENT_URI_WITH_VOICEMAIL, values,
120794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    Calls.NUMBER + " = ? AND " + Calls.COUNTRY_ISO + " IS NULL",
120894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    new String[]{ number });
120994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        } else {
121094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            mContext.getContentResolver().update(Calls.CONTENT_URI_WITH_VOICEMAIL, values,
121194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    Calls.NUMBER + " = ? AND " + Calls.COUNTRY_ISO + " = ?",
121294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    new String[]{ number, countryIso });
121394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
121494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
121594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
121694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Returns the contact information as stored in the call log. */
121794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private ContactInfo getContactInfoFromCallLog(Cursor c) {
121894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        ContactInfo info = new ContactInfo();
121994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        info.lookupUri = UriUtils.parseUriOrNull(c.getString(CallLogQuery.CACHED_LOOKUP_URI));
122094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        info.name = c.getString(CallLogQuery.CACHED_NAME);
122194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        info.type = c.getInt(CallLogQuery.CACHED_NUMBER_TYPE);
122294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        info.label = c.getString(CallLogQuery.CACHED_NUMBER_LABEL);
122394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        String matchedNumber = c.getString(CallLogQuery.CACHED_MATCHED_NUMBER);
122494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        info.number = matchedNumber == null ? c.getString(CallLogQuery.NUMBER) : matchedNumber;
122594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        info.normalizedNumber = c.getString(CallLogQuery.CACHED_NORMALIZED_NUMBER);
122694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        info.photoId = c.getLong(CallLogQuery.CACHED_PHOTO_ID);
122794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        info.photoUri = null;  // We do not cache the photo URI.
122894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        info.formattedNumber = c.getString(CallLogQuery.CACHED_FORMATTED_NUMBER);
122994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        return info;
123094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
123194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
123294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
123394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Returns the call types for the given number of items in the cursor.
123494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
123594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * It uses the next {@code count} rows in the cursor to extract the types.
123694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
123794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * It position in the cursor is unchanged by this function.
123894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
123994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private int[] getCallTypes(Cursor cursor, int count) {
124094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        int position = cursor.getPosition();
124194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        int[] callTypes = new int[count];
124294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        for (int index = 0; index < count; ++index) {
124394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            callTypes[index] = cursor.getInt(CallLogQuery.CALL_TYPE);
124494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            cursor.moveToNext();
124594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
124694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        cursor.moveToPosition(position);
124794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        return callTypes;
124894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
124994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
12508b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn    /**
12518b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     * Determine the features which were enabled for any of the calls that make up a call log
12528b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     * entry.
12538b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     *
12548b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     * @param cursor The cursor.
12558b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     * @param count The number of calls for the current call log entry.
12568b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     * @return The features.
12578b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     */
12588b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn    private int getCallFeatures(Cursor cursor, int count) {
12598b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        int features = Calls.FEATURES_NONE;
12608b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        int position = cursor.getPosition();
12618b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        for (int index = 0; index < count; ++index) {
12628b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn            features |= cursor.getInt(CallLogQuery.FEATURES);
12638b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn            cursor.moveToNext();
12648b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        }
12658b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        cursor.moveToPosition(position);
12668b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        return features;
12678b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn    }
12688b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn
126956cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee    private void setPhoto(CallLogListItemViews views, long photoId, Uri contactUri,
127056cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee            String displayName, String identifier, int contactType) {
127194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        views.quickContactView.assignContactUri(contactUri);
1272cb481aa46e012d1f9f147919b346fbfb16624dabYorke Lee        views.quickContactView.setOverlay(null);
127356cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        DefaultImageRequest request = new DefaultImageRequest(displayName, identifier,
1274cb481aa46e012d1f9f147919b346fbfb16624dabYorke Lee                contactType, true /* isCircular */);
127556cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        mContactPhotoManager.loadThumbnail(views.quickContactView, photoId, false /* darkTheme */,
1276cb481aa46e012d1f9f147919b346fbfb16624dabYorke Lee                true /* isCircular */, request);
127794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
127894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
127956cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee    private void setPhoto(CallLogListItemViews views, Uri photoUri, Uri contactUri,
128056cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee            String displayName, String identifier, int contactType) {
1281034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee        views.quickContactView.assignContactUri(contactUri);
1282cb481aa46e012d1f9f147919b346fbfb16624dabYorke Lee        views.quickContactView.setOverlay(null);
128356cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        DefaultImageRequest request = new DefaultImageRequest(displayName, identifier,
1284cb481aa46e012d1f9f147919b346fbfb16624dabYorke Lee                contactType, true /* isCircular */);
1285034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee        mContactPhotoManager.loadDirectoryPhoto(views.quickContactView, photoUri,
1286cb481aa46e012d1f9f147919b346fbfb16624dabYorke Lee                false /* darkTheme */, true /* isCircular */, request);
1287034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee    }
1288034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee
1289d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn    /**
1290d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn     * Bind a call log entry view for testing purposes.  Also inflates the action view stub so
1291d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn     * unit tests can access the buttons contained within.
1292d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn     *
1293d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn     * @param view The current call log row.
1294d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn     * @param context The current context.
1295d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn     * @param cursor The cursor to bind from.
1296d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn     */
1297d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn    @VisibleForTesting
1298d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn    void bindViewForTest(View view, Context context, Cursor cursor) {
1299d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn        bindStandAloneView(view, context, cursor);
1300d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn        inflateActionViewStub(view);
1301d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn    }
1302034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee
130394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
130494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Sets whether processing of requests for contact details should be enabled.
130594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
130694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * This method should be called in tests to disable such processing of requests when not
130794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * needed.
130894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
130994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @VisibleForTesting
131094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    void disableRequestProcessingForTest() {
131194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mRequestProcessingDisabled = true;
131294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
131394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
131494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @VisibleForTesting
131594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    void injectContactInfoForTest(String number, String countryIso, ContactInfo contactInfo) {
131694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso);
131794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mContactInfoCache.put(numberCountryIso, contactInfo);
131894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
131994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
132094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
132194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    public void addGroup(int cursorPosition, int size, boolean expanded) {
132294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        super.addGroup(cursorPosition, size, expanded);
132394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
132494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
13254dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    /**
13264dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * Stores the day group associated with a call in the call log.
13274dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *
13284dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @param rowId The row Id of the current call.
13294dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @param dayGroup The day group the call belongs in.
13304dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     */
13314dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    @Override
13324dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    public void setDayGroup(long rowId, int dayGroup) {
13334dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        if (!mDayGroups.containsKey(rowId)) {
13344dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            mDayGroups.put(rowId, dayGroup);
13354dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        }
13364dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    }
13374dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn
13384dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    /**
13394dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * Clears the day group associations on re-bind of the call log.
13404dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     */
13414dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    @Override
13424dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    public void clearDayGroups() {
13434dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        mDayGroups.clear();
13444dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    }
13454dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn
134694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /*
134794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Get the number from the Contacts, if available, since sometimes
134894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * the number provided by caller id may not be formatted properly
134994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * depending on the carrier (roaming) in use at the time of the
135094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * incoming call.
135194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Logic : If the caller-id number starts with a "+", use it
135294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     *         Else if the number in the contacts starts with a "+", use that one
135394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     *         Else if the number in the contacts is longer, use that one
135494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
135594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    public String getBetterNumberFromContacts(String number, String countryIso) {
135694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        String matchingNumber = null;
135794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        // Look in the cache first. If it's not found then query the Phones db
135894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso);
135994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        ContactInfo ci = mContactInfoCache.getPossiblyExpired(numberCountryIso);
136094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (ci != null && ci != ContactInfo.EMPTY) {
136194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            matchingNumber = ci.number;
136294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        } else {
136394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            try {
136494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                Cursor phonesCursor = mContext.getContentResolver().query(
136594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number),
136694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        PhoneQuery._PROJECTION, null, null, null);
136794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                if (phonesCursor != null) {
136894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    if (phonesCursor.moveToFirst()) {
136994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        matchingNumber = phonesCursor.getString(PhoneQuery.MATCHED_NUMBER);
137094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    }
137194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                    phonesCursor.close();
137294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                }
137394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            } catch (Exception e) {
137494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                // Use the number from the call log
137594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            }
137694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
137794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (!TextUtils.isEmpty(matchingNumber) &&
137894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                (matchingNumber.startsWith("+")
137994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng                        || matchingNumber.length() > number.length())) {
138094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            number = matchingNumber;
138194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
138294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        return number;
138394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
1384146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
1385146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /**
1386146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * Retrieves the call Ids represented by the current call log row.
1387146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     *
1388146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * @param cursor Call log cursor to retrieve call Ids from.
1389146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * @param groupSize Number of calls associated with the current call log row.
1390146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * @return Array of call Ids.
1391146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     */
1392cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn    private long[] getCallIds(final Cursor cursor, final int groupSize) {
1393146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // We want to restore the position in the cursor at the end.
1394146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        int startingPosition = cursor.getPosition();
1395146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        long[] ids = new long[groupSize];
1396146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // Copy the ids of the rows in the group.
1397146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        for (int index = 0; index < groupSize; ++index) {
1398146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            ids[index] = cursor.getLong(CallLogQuery.ID);
1399146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            cursor.moveToNext();
1400146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
1401146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        cursor.moveToPosition(startingPosition);
1402146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        return ids;
1403146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    }
1404146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
1405146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /**
14064dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * Determines the description for a day group.
14074dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *
14084dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @param group The day group to retrieve the description for.
14094dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @return The day group description.
14104dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     */
14114dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    private CharSequence getGroupDescription(int group) {
14124dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn       if (group == CallLogGroupBuilder.DAY_GROUP_TODAY) {
14131e273313ff938ba0c7294dade433736d3fc5876bTyler Gunn           return mContext.getResources().getString(R.string.call_log_header_today);
14144dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn       } else if (group == CallLogGroupBuilder.DAY_GROUP_YESTERDAY) {
14151e273313ff938ba0c7294dade433736d3fc5876bTyler Gunn           return mContext.getResources().getString(R.string.call_log_header_yesterday);
14164dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn       } else if (group == CallLogGroupBuilder.DAY_GROUP_LAST_WEEK) {
14174dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn           return mContext.getResources().getString(R.string.call_log_header_last_week);
14184dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn       } else {
14194dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn           return mContext.getResources().getString(R.string.call_log_header_other);
14204dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn       }
14214dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    }
14229686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati
14239686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati    public void onBadDataReported(String number) {
14249686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati        mContactInfoCache.expireAll();
14259686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati        mReportedToast.show();
14269686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati    }
142794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng}
1428