CallLogAdapter.java revision 053b9c7a4b2662588706211fd8aa1f8a03ec2901
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.Context; 20c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Chengimport android.content.Intent; 2194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.content.res.Resources; 2294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.database.Cursor; 2394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.net.Uri; 24affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Leeimport android.support.v7.widget.RecyclerView; 25267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Leeimport android.os.Bundle; 2649efd91e50a11dc7bdef8382a0ceac01bc060f77Andrew Leeimport android.os.Trace; 27492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Leeimport android.support.v7.widget.RecyclerView.ViewHolder; 289dc924c8bcc0bc8d996452e9ce3215b5f064962eTyler Gunnimport android.telecom.PhoneAccountHandle; 291e5325f43c98a92f8bfec1dbd9db3d32a91835e9Ihab Awadimport android.telephony.PhoneNumberUtils; 3094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.text.TextUtils; 3194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.view.LayoutInflater; 3294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.view.View; 33b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Leeimport android.view.View.AccessibilityDelegate; 3494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.view.ViewGroup; 3594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.view.ViewTreeObserver; 36b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Leeimport android.view.accessibility.AccessibilityEvent; 3794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 38c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Leeimport com.android.contacts.common.util.PermissionsUtil; 3994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport com.android.dialer.PhoneCallDetails; 4094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport com.android.dialer.PhoneCallDetailsHelper; 419554500572ba82fbd7adb0a1637206ef870ef09eChiao Chengimport com.android.dialer.R; 4274479d448bc39c3534585a627fba603aa89e93caAndrew Leeimport com.android.dialer.contactinfo.ContactInfoCache; 4374479d448bc39c3534585a627fba603aa89e93caAndrew Leeimport com.android.dialer.contactinfo.ContactInfoCache.OnContactInfoChangedListener; 44267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Leeimport com.android.dialer.voicemail.VoicemailPlaybackPresenter; 4556cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee 4694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport com.google.common.annotations.VisibleForTesting; 4794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 48146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunnimport java.util.HashMap; 4994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 5094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng/** 5194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * Adapter class to fill in data for the Call Log. 5294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng */ 53fb585079cc4c522c27f6dd6bf03fd296535960f3Yorke Leepublic class CallLogAdapter extends GroupingListAdapter 5494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng implements ViewTreeObserver.OnPreDrawListener, CallLogGroupBuilder.GroupCreator { 55c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng 5694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng /** Interface used to initiate a refresh of the content. */ 5794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng public interface CallFetcher { 5894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng public void fetchCalls(); 5994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 6094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 6169705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee private static final int VIEW_TYPE_SHOW_CALL_HISTORY_LIST_ITEM = 10; 62affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee private static final int NO_EXPANDED_LIST_ITEM = -1; 638ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn 64704acc087ce359295475a46695c2821c55778344Chiao Cheng protected final Context mContext; 6594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng private final ContactInfoHelper mContactInfoHelper; 66267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee private final VoicemailPlaybackPresenter mVoicemailPlaybackPresenter; 6794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng private final CallFetcher mCallFetcher; 6894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng private ViewTreeObserver mViewTreeObserver = null; 6994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 7074479d448bc39c3534585a627fba603aa89e93caAndrew Lee protected ContactInfoCache mContactInfoCache; 7194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 72bb48628db6fd444460df61be7afa7fb633f47f50Andrew Lee private boolean mIsShowingRecentsTab; 7369705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee 74267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee private static final String KEY_EXPANDED_POSITION = "expanded_position"; 75267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee private static final String KEY_EXPANDED_ROW_ID = "expanded_row_id"; 76267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee 77affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee // Tracks the position of the currently expanded list item. 78affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee private int mCurrentlyExpandedPosition = RecyclerView.NO_POSITION; 79affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee // Tracks the rowId of the currently expanded list item, so the position can be updated if there 80affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee // are any changes to the call log entries, such as additions or removals. 81affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee private long mCurrentlyExpandedRowId = NO_EXPANDED_LIST_ITEM; 82146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn 8394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng /** 844dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * Hashmap, keyed by call Id, used to track the day group for a call. As call log entries are 854dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * put into the primary call groups in {@link com.android.dialer.calllog.CallLogGroupBuilder}, 864dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * they are also assigned a secondary "day group". This hashmap tracks the day group assigned 874dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * to all calls in the call log. This information is used to trigger the display of a day 884dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * group header above the call log entry at the start of a day group. 894dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * Note: Multiple calls are grouped into a single primary "call group" in the call log, and 904dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * the cursor used to bind rows includes all of these calls. When determining if a day group 914dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * change has occurred it is necessary to look at the last entry in the call log to determine 924dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * its day group. This hashmap provides a means of determining the previous day group without 934dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * having to reverse the cursor to the start of the previous day call log entry. 944dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn */ 954dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn private HashMap<Long,Integer> mDayGroups = new HashMap<Long, Integer>(); 964dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn 9794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng private boolean mLoading = true; 9894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 9994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng /** Instance of helper class for managing views. */ 10094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng private final CallLogListItemHelper mCallLogViewsHelper; 10194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 102e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen /** Helper to access Telephony phone number utils class */ 103e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen protected final PhoneNumberUtilsWrapper mPhoneNumberUtilsWrapper; 10494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng /** Helper to group call log entries. */ 10594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng private final CallLogGroupBuilder mCallLogGroupBuilder; 10694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 107146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn /** 108affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee * The OnClickListener used to expand or collapse the action buttons of a call log entry. 109146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn */ 110146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn private final View.OnClickListener mExpandCollapseListener = new View.OnClickListener() { 111146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn @Override 112146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn public void onClick(View v) { 113affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder) v.getTag(); 114affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee 115affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee if (viewHolder == null) { 116affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee return; 117affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee } 118affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee 119053b9c7a4b2662588706211fd8aa1f8a03ec2901Andrew Lee if (mVoicemailPlaybackPresenter != null) { 120053b9c7a4b2662588706211fd8aa1f8a03ec2901Andrew Lee // Always reset the voicemail playback state on expand or collapse. 121053b9c7a4b2662588706211fd8aa1f8a03ec2901Andrew Lee mVoicemailPlaybackPresenter.reset(); 122053b9c7a4b2662588706211fd8aa1f8a03ec2901Andrew Lee } 123bae7b937b6cf6e7eb26d07bec95de38083923614Andrew Lee 124affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee if (viewHolder.getAdapterPosition() == mCurrentlyExpandedPosition) { 125affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee // Hide actions, if the clicked item is the expanded item. 1262f05af35af03de67c1c474cd148719b24fac3552Andrew Lee viewHolder.showActions(false); 127bae7b937b6cf6e7eb26d07bec95de38083923614Andrew Lee 128affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee mCurrentlyExpandedPosition = RecyclerView.NO_POSITION; 129affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee mCurrentlyExpandedRowId = NO_EXPANDED_LIST_ITEM; 130affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee } else { 131affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee expandViewHolderActions(viewHolder); 132affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee } 133affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee 134b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee } 135b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee }; 13668e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn 137affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee private void expandViewHolderActions(CallLogListItemViewHolder viewHolder) { 138affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee // If another item is expanded, notify it that it has changed. Its actions will be 139affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee // hidden when it is re-binded because we change mCurrentlyExpandedPosition below. 140affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee if (mCurrentlyExpandedPosition != RecyclerView.NO_POSITION) { 141affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee notifyItemChanged(mCurrentlyExpandedPosition); 142affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee } 143affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee // Show the actions for the clicked list item. 1442f05af35af03de67c1c474cd148719b24fac3552Andrew Lee viewHolder.showActions(true); 145affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee mCurrentlyExpandedPosition = viewHolder.getAdapterPosition(); 146affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee mCurrentlyExpandedRowId = viewHolder.rowId; 147affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee } 14874479d448bc39c3534585a627fba603aa89e93caAndrew Lee 149affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee /** 150affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee * Expand the actions on a list item when focused in Talkback mode, to aid discoverability. 151affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee */ 152b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee private AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() { 153b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee @Override 154c940eada912f952a95d693ae6aab48ef08ef7319Andrew Lee public boolean onRequestSendAccessibilityEvent( 155c940eada912f952a95d693ae6aab48ef08ef7319Andrew Lee ViewGroup host, View child, AccessibilityEvent event) { 156b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) { 157c940eada912f952a95d693ae6aab48ef08ef7319Andrew Lee // Only expand if actions are not already expanded, because triggering the expand 158c940eada912f952a95d693ae6aab48ef08ef7319Andrew Lee // function on clicks causes the action views to lose the focus indicator. 159c940eada912f952a95d693ae6aab48ef08ef7319Andrew Lee CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder) host.getTag(); 160c940eada912f952a95d693ae6aab48ef08ef7319Andrew Lee if (mCurrentlyExpandedPosition != viewHolder.getAdapterPosition()) { 161c940eada912f952a95d693ae6aab48ef08ef7319Andrew Lee expandViewHolderActions((CallLogListItemViewHolder) host.getTag()); 162c940eada912f952a95d693ae6aab48ef08ef7319Andrew Lee } 16368e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn } 164b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee return super.onRequestSendAccessibilityEvent(host, child, event); 165146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn } 166146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn }; 167146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn 168affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee protected final OnContactInfoChangedListener mOnContactInfoChangedListener = 169affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee new OnContactInfoChangedListener() { 170affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee @Override 171affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee public void onContactInfoChanged() { 172affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee notifyDataSetChanged(); 173affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee } 174affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee }; 175affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee 17694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng @Override 17794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng public boolean onPreDraw() { 17894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng // We only wanted to listen for the first draw (and this is it). 17994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng unregisterPreDrawListener(); 180c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Lee if (PermissionsUtil.hasContactsPermissions(mContext)) { 181c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Lee mContactInfoCache.start(); 182c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Lee } 18394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng return true; 18494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 18594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 186c6fde8d1b9a4e586ca65b82e9911089a9da14508Andrew Lee public CallLogAdapter( 187c6fde8d1b9a4e586ca65b82e9911089a9da14508Andrew Lee Context context, 188c6fde8d1b9a4e586ca65b82e9911089a9da14508Andrew Lee CallFetcher callFetcher, 189c6fde8d1b9a4e586ca65b82e9911089a9da14508Andrew Lee ContactInfoHelper contactInfoHelper, 190267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee VoicemailPlaybackPresenter voicemailPlaybackPresenter, 1912f05af35af03de67c1c474cd148719b24fac3552Andrew Lee boolean isShowingRecentsTab) { 19294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng super(context); 19394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 19494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng mContext = context; 19594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng mCallFetcher = callFetcher; 19694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng mContactInfoHelper = contactInfoHelper; 197267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee mVoicemailPlaybackPresenter = voicemailPlaybackPresenter; 198bb48628db6fd444460df61be7afa7fb633f47f50Andrew Lee mIsShowingRecentsTab = isShowingRecentsTab; 199b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati 20074479d448bc39c3534585a627fba603aa89e93caAndrew Lee mContactInfoCache = new ContactInfoCache( 20174479d448bc39c3534585a627fba603aa89e93caAndrew Lee mContactInfoHelper, mOnContactInfoChangedListener); 202c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Lee if (!PermissionsUtil.hasContactsPermissions(context)) { 203c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Lee mContactInfoCache.disableRequestProcessing(); 204c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Lee } 20594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 20694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng Resources resources = mContext.getResources(); 20794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng CallTypeHelper callTypeHelper = new CallTypeHelper(resources); 20894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 209e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen mPhoneNumberUtilsWrapper = new PhoneNumberUtilsWrapper(mContext); 210e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen PhoneCallDetailsHelper phoneCallDetailsHelper = 211e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen new PhoneCallDetailsHelper(mContext, resources, mPhoneNumberUtilsWrapper); 21249efd91e50a11dc7bdef8382a0ceac01bc060f77Andrew Lee mCallLogViewsHelper = new CallLogListItemHelper(phoneCallDetailsHelper, resources); 21394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng mCallLogGroupBuilder = new CallLogGroupBuilder(this); 21494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 21594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 216267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee public void onSaveInstanceState(Bundle outState) { 217267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee outState.putInt(KEY_EXPANDED_POSITION, mCurrentlyExpandedPosition); 218267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee outState.putLong(KEY_EXPANDED_ROW_ID, mCurrentlyExpandedRowId); 219267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee } 220267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee 221267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee public void onRestoreInstanceState(Bundle savedInstanceState) { 222267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee if (savedInstanceState != null) { 223267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee mCurrentlyExpandedPosition = 224267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee savedInstanceState.getInt(KEY_EXPANDED_POSITION, RecyclerView.NO_POSITION); 225267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee mCurrentlyExpandedRowId = 226267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee savedInstanceState.getLong(KEY_EXPANDED_ROW_ID, NO_EXPANDED_LIST_ITEM); 227267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee } 228267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee } 229267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee 23094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng /** 23194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * Requery on background thread when {@link Cursor} changes. 23294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng */ 23394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng @Override 23494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng protected void onContentChanged() { 23594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng mCallFetcher.fetchCalls(); 23694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 23794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 238fb585079cc4c522c27f6dd6bf03fd296535960f3Yorke Lee public void setLoading(boolean loading) { 23994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng mLoading = loading; 24094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 24194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 24294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng public boolean isEmpty() { 24394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng if (mLoading) { 24494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng // We don't want the empty state to show when loading. 24594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng return false; 24694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } else { 247492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee return getItemCount() == 0; 24894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 24994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 25094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 25194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng /** 25294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * Stop receiving onPreDraw() notifications. 25394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng */ 25494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng private void unregisterPreDrawListener() { 25594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng if (mViewTreeObserver != null && mViewTreeObserver.isAlive()) { 25694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng mViewTreeObserver.removeOnPreDrawListener(this); 25794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 25894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng mViewTreeObserver = null; 25994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 26094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 26194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng public void invalidateCache() { 26274479d448bc39c3534585a627fba603aa89e93caAndrew Lee mContactInfoCache.invalidate(); 26394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 26494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng // Restart the request-processing thread after the next draw. 26594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng unregisterPreDrawListener(); 26694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 26794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 26874479d448bc39c3534585a627fba603aa89e93caAndrew Lee public void pauseCache() { 26974479d448bc39c3534585a627fba603aa89e93caAndrew Lee mContactInfoCache.stop(); 27094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 27194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 27294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng @Override 27394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng protected void addGroups(Cursor cursor) { 27494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng mCallLogGroupBuilder.addGroups(cursor); 27594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 27694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 27794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng @Override 278492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 27969705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee if (viewType == VIEW_TYPE_SHOW_CALL_HISTORY_LIST_ITEM) { 28069705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee return ShowCallHistoryViewHolder.create(mContext, parent); 28169705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee } 2829afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn return createCallLogEntryViewHolder(parent); 2839afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn } 2849afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn 2859afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn /** 2869afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn * Creates a new call log entry {@link ViewHolder}. 2879afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn * 2889afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn * @param parent the parent view. 2899afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn * @return The {@link ViewHolder}. 2909afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn */ 2919afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn private ViewHolder createCallLogEntryViewHolder(ViewGroup parent) { 292492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee LayoutInflater inflater = LayoutInflater.from(mContext); 2932ff08a8f8d4762ab5d0aebb0b69079f0b8d20b3eYorke Lee View view = inflater.inflate(R.layout.call_log_list_item, parent, false); 294c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee 295c1b7d0ae8cdfc0f0dddb5c2bb45c8239ffc6a264Andrew Lee CallLogListItemViewHolder viewHolder = CallLogListItemViewHolder.create( 296c1b7d0ae8cdfc0f0dddb5c2bb45c8239ffc6a264Andrew Lee view, 297c1b7d0ae8cdfc0f0dddb5c2bb45c8239ffc6a264Andrew Lee mContext, 298bae7b937b6cf6e7eb26d07bec95de38083923614Andrew Lee mExpandCollapseListener, 299c1b7d0ae8cdfc0f0dddb5c2bb45c8239ffc6a264Andrew Lee mPhoneNumberUtilsWrapper, 300267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee mCallLogViewsHelper, 301267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee mVoicemailPlaybackPresenter); 302affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee 303affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee viewHolder.callLogEntryView.setTag(viewHolder); 304affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee viewHolder.callLogEntryView.setAccessibilityDelegate(mAccessibilityDelegate); 305affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee 306c1b7d0ae8cdfc0f0dddb5c2bb45c8239ffc6a264Andrew Lee viewHolder.primaryActionView.setTag(viewHolder); 307c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee 308c1b7d0ae8cdfc0f0dddb5c2bb45c8239ffc6a264Andrew Lee return viewHolder; 30994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 31094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 31194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng /** 31294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * Binds the views in the entry to the data in the call log. 313a9a82f52cbcadd0b9a4aafa0c785c0d6af629f1cSantos Cordon * TODO: This gets called 20-30 times when Dialer starts up for a single call log entry and 314a9a82f52cbcadd0b9a4aafa0c785c0d6af629f1cSantos Cordon * should not. It invokes cross-process methods and the repeat execution can get costly. 31594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * 3162ff08a8f8d4762ab5d0aebb0b69079f0b8d20b3eYorke Lee * @param callLogItemView the view corresponding to this entry 31794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * @param count the number of entries in the current item, greater than 1 if it is a group 31894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng */ 319492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee public void onBindViewHolder(ViewHolder viewHolder, int position) { 32069705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee if (getItemViewType(position) == VIEW_TYPE_SHOW_CALL_HISTORY_LIST_ITEM) { 32169705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee return; 32269705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee } 32349efd91e50a11dc7bdef8382a0ceac01bc060f77Andrew Lee Trace.beginSection("onBindViewHolder: " + position); 324492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee Cursor c = (Cursor) getItem(position); 325492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee if (c == null) { 32649efd91e50a11dc7bdef8382a0ceac01bc060f77Andrew Lee Trace.endSection(); 327492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee return; 328492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee } 329492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee int count = getGroupSize(position); 330492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee 33194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng final String number = c.getString(CallLogQuery.NUMBER); 332719a7adde25e0a717816b00668c16c3a1e3c5518Jay Shrauner final int numberPresentation = c.getInt(CallLogQuery.NUMBER_PRESENTATION); 333b2eebafbc1f1e26b5178b2858ca335467b4bc341Nancy Chen final PhoneAccountHandle accountHandle = PhoneAccountUtils.getAccount( 334b2eebafbc1f1e26b5178b2858ca335467b4bc341Nancy Chen c.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME), 335b2eebafbc1f1e26b5178b2858ca335467b4bc341Nancy Chen c.getString(CallLogQuery.ACCOUNT_ID)); 33694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng final String countryIso = c.getString(CallLogQuery.COUNTRY_ISO); 337c1fc077754e99bff54bfd7e155ba5c8dd95cf773Andrew Lee final ContactInfo cachedContactInfo = mContactInfoHelper.getContactInfo(c); 33856cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee final boolean isVoicemailNumber = 339e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen mPhoneNumberUtilsWrapper.isVoicemailNumber(accountHandle, number); 34056cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee 34114cfa66d6df53303c280194d661c0b32838aa417Andrew Lee // Note: Binding of the action buttons is done as required in configureActionViews when the 34214cfa66d6df53303c280194d661c0b32838aa417Andrew Lee // user expands the actions ViewStub. 343146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn 34474479d448bc39c3534585a627fba603aa89e93caAndrew Lee ContactInfo info = ContactInfo.EMPTY; 34574479d448bc39c3534585a627fba603aa89e93caAndrew Lee if (PhoneNumberUtilsWrapper.canPlaceCallsTo(number, numberPresentation) 34674479d448bc39c3534585a627fba603aa89e93caAndrew Lee && !isVoicemailNumber) { 34774479d448bc39c3534585a627fba603aa89e93caAndrew Lee // Lookup contacts with this number 34874479d448bc39c3534585a627fba603aa89e93caAndrew Lee info = mContactInfoCache.getValue(number, countryIso, cachedContactInfo); 34994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 3501e5325f43c98a92f8bfec1dbd9db3d32a91835e9Ihab Awad CharSequence formattedNumber = info.formattedNumber == null 3514f8c39ab99b575cf6e2eb8ea3a9847d51603e244Brian Attwell ? null : PhoneNumberUtils.createTtsSpannable(info.formattedNumber); 352edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee 353edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee final PhoneCallDetails details = new PhoneCallDetails( 354edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee mContext, number, numberPresentation, formattedNumber, isVoicemailNumber); 355edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee details.accountHandle = accountHandle; 356edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee details.callTypes = getCallTypes(c, count); 357edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee details.countryIso = countryIso; 358edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee details.date = c.getLong(CallLogQuery.DATE); 359edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee details.duration = c.getLong(CallLogQuery.DURATION); 360edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee details.features = getCallFeatures(c, count); 361edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee details.geocode = c.getString(CallLogQuery.GEOCODED_LOCATION); 362edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee details.transcription = c.getString(CallLogQuery.TRANSCRIPTION); 363edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee 3648b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn if (!c.isNull(CallLogQuery.DATA_USAGE)) { 365edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee details.dataUsage = c.getLong(CallLogQuery.DATA_USAGE); 3668b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn } 3678b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn 368edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee if (!TextUtils.isEmpty(info.name)) { 369edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee details.contactUri = info.lookupUri; 370edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee details.name = info.name; 371edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee details.numberType = info.type; 372edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee details.numberLabel = info.label; 373edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee details.photoUri = info.photoUri; 374edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee details.sourceType = info.sourceType; 3752f05af35af03de67c1c474cd148719b24fac3552Andrew Lee details.objectId = info.objectId; 376edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee } 377704acc087ce359295475a46695c2821c55778344Chiao Cheng 378edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee CallLogListItemViewHolder views = (CallLogListItemViewHolder) viewHolder; 3795a9cd71b8ea670cd7c9aebd3dba27ea8cbe769dfAndrew Lee views.info = info; 380edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee views.rowId = c.getLong(CallLogQuery.ID); 381edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee // Store values used when the actions ViewStub is inflated on expansion. 382edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee views.number = number; 383edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee views.numberPresentation = numberPresentation; 384edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee views.callType = c.getInt(CallLogQuery.CALL_TYPE); 385edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee views.accountHandle = accountHandle; 386edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee views.voicemailUri = c.getString(CallLogQuery.VOICEMAIL_URI); 387edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee // Stash away the Ids of the calls so that we can support deleting a row in the call log. 388edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee views.callIds = getCallIds(c, count); 38955733814f213809baaa8eaa8984ff026bdb08b4eAnthony Lee 390edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee // Default case: an item in the call log. 391edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee views.primaryActionView.setVisibility(View.VISIBLE); 3929686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati 393edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee // Check if the day group has changed and display a header if necessary. 394edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee int currentGroup = getDayGroupForCall(views.rowId); 395edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee int previousGroup = getPreviousDayGroup(c); 396edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee if (currentGroup != previousGroup) { 397edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee views.dayGroupHeader.setVisibility(View.VISIBLE); 398edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee views.dayGroupHeader.setText(getGroupDescription(currentGroup)); 39994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } else { 400edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee views.dayGroupHeader.setVisibility(View.GONE); 40194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 40294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 403b0b57a10fbb9bec5c80d7adad8f65750a2f96e1bAndrew Lee mCallLogViewsHelper.setPhoneCallDetails(mContext, views, details); 404b0b57a10fbb9bec5c80d7adad8f65750a2f96e1bAndrew Lee 405edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee // Update the expanded position if the rowIds match, in case ViewHolders were added/removed. 406edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee // Then restore the state of the row on rebind. 407edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee if (mCurrentlyExpandedRowId == views.rowId) { 408edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee mCurrentlyExpandedPosition = position; 409edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee } 4102f05af35af03de67c1c474cd148719b24fac3552Andrew Lee views.showActions(mCurrentlyExpandedPosition == position); 411034a2b329e469bf6888fbbcf91992f974015c2a8Yorke Lee 41256cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee String nameForDefaultImage = null; 413edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee if (TextUtils.isEmpty(info.name)) { 41449efd91e50a11dc7bdef8382a0ceac01bc060f77Andrew Lee nameForDefaultImage = details.displayNumber; 41556cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee } else { 416edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee nameForDefaultImage = info.name; 41756cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee } 418edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee views.setPhoto(info.photoId, info.photoUri, info.lookupUri, nameForDefaultImage, 419edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee isVoicemailNumber, mContactInfoHelper.isBusiness(info.sourceType)); 42056cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee 421edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee mCallLogViewsHelper.setPhoneCallDetails(mContext, views, details); 422c1b7d0ae8cdfc0f0dddb5c2bb45c8239ffc6a264Andrew Lee 42394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng // Listen for the first draw 42494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng if (mViewTreeObserver == null) { 425492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee mViewTreeObserver = views.rootView.getViewTreeObserver(); 42694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng mViewTreeObserver.addOnPreDrawListener(this); 42794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 42849efd91e50a11dc7bdef8382a0ceac01bc060f77Andrew Lee Trace.endSection(); 429c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng } 430c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng 43169705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee @Override 43269705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee public int getItemCount() { 433bb48628db6fd444460df61be7afa7fb633f47f50Andrew Lee return super.getItemCount() + (isShowingRecentsTab() ? 1 : 0); 43469705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee } 43569705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee 43669705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee @Override 43769705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee public int getItemViewType(int position) { 438bb48628db6fd444460df61be7afa7fb633f47f50Andrew Lee if (position == getItemCount() - 1 && isShowingRecentsTab()) { 43969705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee return VIEW_TYPE_SHOW_CALL_HISTORY_LIST_ITEM; 44069705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee } 44169705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee return super.getItemViewType(position); 44269705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee } 44369705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee 444bb48628db6fd444460df61be7afa7fb633f47f50Andrew Lee protected boolean isShowingRecentsTab() { 445bb48628db6fd444460df61be7afa7fb633f47f50Andrew Lee return mIsShowingRecentsTab; 44669705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee } 44769705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee 448146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn /** 4494dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * Retrieves the day group of the previous call in the call log. Used to determine if the day 4504dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * group has changed and to trigger display of the day group text. 4514dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * 4524dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * @param cursor The call log cursor. 4534dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * @return The previous day group, or DAY_GROUP_NONE if this is the first call. 4544dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn */ 4554dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn private int getPreviousDayGroup(Cursor cursor) { 4564dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn // We want to restore the position in the cursor at the end. 4574dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn int startingPosition = cursor.getPosition(); 4584dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn int dayGroup = CallLogGroupBuilder.DAY_GROUP_NONE; 4594dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn if (cursor.moveToPrevious()) { 4604dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn long previousRowId = cursor.getLong(CallLogQuery.ID); 4614dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn dayGroup = getDayGroupForCall(previousRowId); 4624dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn } 4634dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn cursor.moveToPosition(startingPosition); 4644dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn return dayGroup; 4654dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn } 4664dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn 4674dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn /** 4684dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * Given a call Id, look up the day group that the call belongs to. The day group data is 4694dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * populated in {@link com.android.dialer.calllog.CallLogGroupBuilder}. 4704dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * 4714dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * @param callId The call to retrieve the day group for. 4724dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * @return The day group for the call. 4734dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn */ 4744dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn private int getDayGroupForCall(long callId) { 4754dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn if (mDayGroups.containsKey(callId)) { 4764dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn return mDayGroups.get(callId); 4774dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn } 4784dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn return CallLogGroupBuilder.DAY_GROUP_NONE; 4794dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn } 48081c3829f8a9377cb2e93c1fa6d223d223b78f371Andrew Lee 4814dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn /** 48294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * Returns the call types for the given number of items in the cursor. 48394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * <p> 48494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * It uses the next {@code count} rows in the cursor to extract the types. 48594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * <p> 48694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * It position in the cursor is unchanged by this function. 48794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng */ 48894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng private int[] getCallTypes(Cursor cursor, int count) { 48994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng int position = cursor.getPosition(); 49094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng int[] callTypes = new int[count]; 49194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng for (int index = 0; index < count; ++index) { 49294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng callTypes[index] = cursor.getInt(CallLogQuery.CALL_TYPE); 49394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng cursor.moveToNext(); 49494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 49594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng cursor.moveToPosition(position); 49694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng return callTypes; 49794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 49894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 4998b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn /** 5008b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn * Determine the features which were enabled for any of the calls that make up a call log 5018b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn * entry. 5028b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn * 5038b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn * @param cursor The cursor. 5048b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn * @param count The number of calls for the current call log entry. 5058b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn * @return The features. 5068b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn */ 5078b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn private int getCallFeatures(Cursor cursor, int count) { 50803610993bf2adf12a6962c32851095551ffd0043Yorke Lee int features = 0; 5098b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn int position = cursor.getPosition(); 5108b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn for (int index = 0; index < count; ++index) { 5118b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn features |= cursor.getInt(CallLogQuery.FEATURES); 5128b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn cursor.moveToNext(); 5138b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn } 5148b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn cursor.moveToPosition(position); 5158b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn return features; 5168b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn } 5178b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn 518d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn /** 51994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * Sets whether processing of requests for contact details should be enabled. 52074479d448bc39c3534585a627fba603aa89e93caAndrew Lee * 52194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * This method should be called in tests to disable such processing of requests when not 52294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * needed. 52394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng */ 52494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng @VisibleForTesting 52594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng void disableRequestProcessingForTest() { 52674479d448bc39c3534585a627fba603aa89e93caAndrew Lee // TODO: Remove this and test the cache directly. 527c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Lee mContactInfoCache.disableRequestProcessing(); 52894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 52994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 53094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng @VisibleForTesting 53194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng void injectContactInfoForTest(String number, String countryIso, ContactInfo contactInfo) { 53274479d448bc39c3534585a627fba603aa89e93caAndrew Lee // TODO: Remove this and test the cache directly. 53374479d448bc39c3534585a627fba603aa89e93caAndrew Lee mContactInfoCache.injectContactInfoForTest(number, countryIso, contactInfo); 53494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 53594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 53694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng @Override 53794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng public void addGroup(int cursorPosition, int size, boolean expanded) { 53894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng super.addGroup(cursorPosition, size, expanded); 53994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng } 54094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng 5414dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn /** 5424dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * Stores the day group associated with a call in the call log. 5434dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * 5444dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * @param rowId The row Id of the current call. 5454dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * @param dayGroup The day group the call belongs in. 5464dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn */ 5474dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn @Override 5484dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn public void setDayGroup(long rowId, int dayGroup) { 5494dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn if (!mDayGroups.containsKey(rowId)) { 5504dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn mDayGroups.put(rowId, dayGroup); 5514dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn } 5524dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn } 5534dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn 5544dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn /** 5554dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * Clears the day group associations on re-bind of the call log. 5564dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn */ 5574dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn @Override 5584dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn public void clearDayGroups() { 5594dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn mDayGroups.clear(); 5604dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn } 5614dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn 562146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn /** 563146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn * Retrieves the call Ids represented by the current call log row. 564146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn * 565146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn * @param cursor Call log cursor to retrieve call Ids from. 566146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn * @param groupSize Number of calls associated with the current call log row. 567146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn * @return Array of call Ids. 568146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn */ 569cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn private long[] getCallIds(final Cursor cursor, final int groupSize) { 570146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn // We want to restore the position in the cursor at the end. 571146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn int startingPosition = cursor.getPosition(); 572146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn long[] ids = new long[groupSize]; 573146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn // Copy the ids of the rows in the group. 574146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn for (int index = 0; index < groupSize; ++index) { 575146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn ids[index] = cursor.getLong(CallLogQuery.ID); 576146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn cursor.moveToNext(); 577146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn } 578146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn cursor.moveToPosition(startingPosition); 579146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn return ids; 580146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn } 581146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn 582146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn /** 5834dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * Determines the description for a day group. 5844dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * 5854dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * @param group The day group to retrieve the description for. 5864dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn * @return The day group description. 5874dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn */ 5884dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn private CharSequence getGroupDescription(int group) { 5894dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn if (group == CallLogGroupBuilder.DAY_GROUP_TODAY) { 5901e273313ff938ba0c7294dade433736d3fc5876bTyler Gunn return mContext.getResources().getString(R.string.call_log_header_today); 5914dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn } else if (group == CallLogGroupBuilder.DAY_GROUP_YESTERDAY) { 5921e273313ff938ba0c7294dade433736d3fc5876bTyler Gunn return mContext.getResources().getString(R.string.call_log_header_yesterday); 5934dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn } else { 5944dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn return mContext.getResources().getString(R.string.call_log_header_other); 5954dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn } 5964dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn } 59794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng} 598