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