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