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