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
195f1c7dbf86603f534fbacdc96bab30d683913f4fBrandon Maxwellimport com.google.common.annotations.VisibleForTesting;
205f1c7dbf86603f534fbacdc96bab30d683913f4fBrandon Maxwell
2194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.content.Context;
22c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Chengimport android.content.Intent;
23bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chenimport android.content.SharedPreferences;
2494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.content.res.Resources;
2594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.database.Cursor;
2694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.net.Uri;
27267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Leeimport android.os.Bundle;
2849efd91e50a11dc7bdef8382a0ceac01bc060f77Andrew Leeimport android.os.Trace;
29bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chenimport android.preference.PreferenceManager;
3003aaf3894d8af53f241d1189c504e44c538100d4Nancy Chenimport android.provider.CallLog;
315f1c7dbf86603f534fbacdc96bab30d683913f4fBrandon Maxwellimport android.provider.ContactsContract.CommonDataKinds.Phone;
325f1c7dbf86603f534fbacdc96bab30d683913f4fBrandon Maxwellimport android.support.v7.widget.RecyclerView;
33492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Leeimport android.support.v7.widget.RecyclerView.ViewHolder;
349dc924c8bcc0bc8d996452e9ce3215b5f064962eTyler Gunnimport android.telecom.PhoneAccountHandle;
351e5325f43c98a92f8bfec1dbd9db3d32a91835e9Ihab Awadimport android.telephony.PhoneNumberUtils;
36bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chenimport android.telephony.TelephonyManager;
3794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.text.TextUtils;
38486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaaimport android.util.ArrayMap;
3994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.view.LayoutInflater;
4094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.view.View;
41b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Leeimport android.view.View.AccessibilityDelegate;
4294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport android.view.ViewGroup;
43b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Leeimport android.view.accessibility.AccessibilityEvent;
4494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
45240523d3e1b4502326c8d0d313dd1787aa8ff024Victor Changimport com.android.contacts.common.ContactsUtils;
4617df9323e45ae5984b6df25b788a9cbffb51e8abBrandon Maxwellimport com.android.contacts.common.compat.CompatUtils;
478104b41f9ca85c2615e9aa52cb012b5868a0314fBrandon Maxwellimport com.android.contacts.common.compat.PhoneNumberUtilsCompat;
485f1c7dbf86603f534fbacdc96bab30d683913f4fBrandon Maxwellimport com.android.contacts.common.preference.ContactsPreferences;
49c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Leeimport com.android.contacts.common.util.PermissionsUtil;
5017df9323e45ae5984b6df25b788a9cbffb51e8abBrandon Maxwellimport com.android.dialer.DialtactsActivity;
5194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Chengimport com.android.dialer.PhoneCallDetails;
529554500572ba82fbd7adb0a1637206ef870ef09eChiao Chengimport com.android.dialer.R;
5337aa2f3d402bdb233d3c922fcde4f9aa6a262d68Nancy Chenimport com.android.dialer.calllog.calllogcache.CallLogCache;
5474479d448bc39c3534585a627fba603aa89e93caAndrew Leeimport com.android.dialer.contactinfo.ContactInfoCache;
5574479d448bc39c3534585a627fba603aa89e93caAndrew Leeimport com.android.dialer.contactinfo.ContactInfoCache.OnContactInfoChangedListener;
569bd094118e920b732394c29657f26b062f3e916bAnne Rongimport com.android.dialer.database.FilteredNumberAsyncQueryHandler;
5717df9323e45ae5984b6df25b788a9cbffb51e8abBrandon Maxwellimport com.android.dialer.database.VoicemailArchiveContract;
58d81cc6c64f3213f571c1f1e7a5c7e59b71491fb0Brandon Maxwellimport com.android.dialer.filterednumber.BlockNumberDialogFragment.Callback;
59d81cc6c64f3213f571c1f1e7a5c7e59b71491fb0Brandon Maxwellimport com.android.dialer.logging.InteractionEvent;
60d81cc6c64f3213f571c1f1e7a5c7e59b71491fb0Brandon Maxwellimport com.android.dialer.logging.Logger;
61486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaaimport com.android.dialer.service.ExtendedBlockingButtonRenderer;
62d3f6a6c56dec7d47bae1121ed1030f67c26736feAndrew Leeimport com.android.dialer.util.PhoneNumberUtil;
63267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Leeimport com.android.dialer.voicemail.VoicemailPlaybackPresenter;
6456cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee
65146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunnimport java.util.HashMap;
66486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaaimport java.util.Map;
6794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
6894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng/**
6994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng * Adapter class to fill in data for the Call Log.
7094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng */
71fb585079cc4c522c27f6dd6bf03fd296535960f3Yorke Leepublic class CallLogAdapter extends GroupingListAdapter
72601eadd8518b2a3683c50850af2a6db8147ec61aYorke Lee        implements CallLogGroupBuilder.GroupCreator,
73486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa                VoicemailPlaybackPresenter.OnVoicemailDeletedListener,
74486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa                ExtendedBlockingButtonRenderer.Listener {
75c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
766b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi    // Types of activities the call log adapter is used for
776b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi    public static final int ACTIVITY_TYPE_CALL_LOG = 1;
786b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi    public static final int ACTIVITY_TYPE_ARCHIVE = 2;
796b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi    public static final int ACTIVITY_TYPE_DIALTACTS = 3;
806b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi
8194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Interface used to initiate a refresh of the content. */
8294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    public interface CallFetcher {
8394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        public void fetchCalls();
8494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
8594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
86affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee    private static final int NO_EXPANDED_LIST_ITEM = -1;
87dfc69c43df7c46fb6f059c3ac7f61badd2a4b820Andrew Lee    // ConcurrentHashMap doesn't store null values. Use this value for numbers which aren't blocked.
88dfc69c43df7c46fb6f059c3ac7f61badd2a4b820Andrew Lee    private static final int NOT_BLOCKED = -1;
898ef8020b8b792026a8dd15e029055f7d5e2d48f6Tyler Gunn
90bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    private static final int VOICEMAIL_PROMO_CARD_POSITION = 0;
91ab90a18e2f05c7ae4158b770a9fbe9cbe4544597Andrew Lee
92ab90a18e2f05c7ae4158b770a9fbe9cbe4544597Andrew Lee    protected static final int VIEW_TYPE_NORMAL = 0;
93ab90a18e2f05c7ae4158b770a9fbe9cbe4544597Andrew Lee    private static final int VIEW_TYPE_VOICEMAIL_PROMO_CARD = 1;
94bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen
95bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    /**
96bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * The key for the show voicemail promo card preference which will determine whether the promo
97bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * card was permanently dismissed or not.
98bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     */
99bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    private static final String SHOW_VOICEMAIL_PROMO_CARD = "show_voicemail_promo_card";
100bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    private static final boolean SHOW_VOICEMAIL_PROMO_CARD_DEFAULT = true;
101bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen
102704acc087ce359295475a46695c2821c55778344Chiao Cheng    protected final Context mContext;
10394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private final ContactInfoHelper mContactInfoHelper;
104a4adb2c035690a1c9600a20c2485886d9d5991d0Andrew Lee    protected final VoicemailPlaybackPresenter mVoicemailPlaybackPresenter;
10594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private final CallFetcher mCallFetcher;
1069bd094118e920b732394c29657f26b062f3e916bAnne Rong    private final FilteredNumberAsyncQueryHandler mFilteredNumberAsyncQueryHandler;
107486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa    private final Map<String, Boolean> mBlockedNumberCache = new ArrayMap<>();
10894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
10974479d448bc39c3534585a627fba603aa89e93caAndrew Lee    protected ContactInfoCache mContactInfoCache;
11094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
1116b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi    private final int mActivityType;
11269705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee
113267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee    private static final String KEY_EXPANDED_POSITION = "expanded_position";
114267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee    private static final String KEY_EXPANDED_ROW_ID = "expanded_row_id";
115267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee
116affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee    // Tracks the position of the currently expanded list item.
117affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee    private int mCurrentlyExpandedPosition = RecyclerView.NO_POSITION;
118affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee    // Tracks the rowId of the currently expanded list item, so the position can be updated if there
119affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee    // are any changes to the call log entries, such as additions or removals.
120affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee    private long mCurrentlyExpandedRowId = NO_EXPANDED_LIST_ITEM;
1212d588b857347fda465a963742c4f61e4014f3441Nancy Chen    private int mHiddenPosition = RecyclerView.NO_POSITION;
1222d588b857347fda465a963742c4f61e4014f3441Nancy Chen    private Uri mHiddenItemUri = null;
1232d588b857347fda465a963742c4f61e4014f3441Nancy Chen    private boolean mPendingHide = false;
124146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
12594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
1264dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  Hashmap, keyed by call Id, used to track the day group for a call.  As call log entries are
1274dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  put into the primary call groups in {@link com.android.dialer.calllog.CallLogGroupBuilder},
1284dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  they are also assigned a secondary "day group".  This hashmap tracks the day group assigned
1294dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  to all calls in the call log.  This information is used to trigger the display of a day
1304dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  group header above the call log entry at the start of a day group.
1314dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  Note: Multiple calls are grouped into a single primary "call group" in the call log, and
1324dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  the cursor used to bind rows includes all of these calls.  When determining if a day group
1334dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  change has occurred it is necessary to look at the last entry in the call log to determine
1344dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  its day group.  This hashmap provides a means of determining the previous day group without
1354dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *  having to reverse the cursor to the start of the previous day call log entry.
1364dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     */
1375f1c7dbf86603f534fbacdc96bab30d683913f4fBrandon Maxwell    private HashMap<Long, Integer> mDayGroups = new HashMap<>();
1384dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn
13994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private boolean mLoading = true;
14094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
141bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    private SharedPreferences mPrefs;
142bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen
1435f1c7dbf86603f534fbacdc96bab30d683913f4fBrandon Maxwell    private ContactsPreferences mContactsPreferences;
1445f1c7dbf86603f534fbacdc96bab30d683913f4fBrandon Maxwell
1450599e880630892becf1a1991e6712e0e6d9df3c8Andrew Lee    protected boolean mShowVoicemailPromoCard = false;
146bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen
14794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Instance of helper class for managing views. */
148d3f6a6c56dec7d47bae1121ed1030f67c26736feAndrew Lee    private final CallLogListItemHelper mCallLogListItemHelper;
149d3f6a6c56dec7d47bae1121ed1030f67c26736feAndrew Lee
15037aa2f3d402bdb233d3c922fcde4f9aa6a262d68Nancy Chen    /** Cache for repeated requests to Telecom/Telephony. */
15137aa2f3d402bdb233d3c922fcde4f9aa6a262d68Nancy Chen    protected final CallLogCache mCallLogCache;
15294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
15394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /** Helper to group call log entries. */
15494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private final CallLogGroupBuilder mCallLogGroupBuilder;
15594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
156146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /**
157affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee     * The OnClickListener used to expand or collapse the action buttons of a call log entry.
158146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     */
159146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    private final View.OnClickListener mExpandCollapseListener = new View.OnClickListener() {
160146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        @Override
161146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        public void onClick(View v) {
162affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee            CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder) v.getTag();
163affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee            if (viewHolder == null) {
164affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee                return;
165affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee            }
166affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee
167053b9c7a4b2662588706211fd8aa1f8a03ec2901Andrew Lee            if (mVoicemailPlaybackPresenter != null) {
168053b9c7a4b2662588706211fd8aa1f8a03ec2901Andrew Lee                // Always reset the voicemail playback state on expand or collapse.
16985647649a10d680faeb2e73a3d191191058b7d66Nancy Chen                mVoicemailPlaybackPresenter.resetAll();
170053b9c7a4b2662588706211fd8aa1f8a03ec2901Andrew Lee            }
171bae7b937b6cf6e7eb26d07bec95de38083923614Andrew Lee
172affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee            if (viewHolder.getAdapterPosition() == mCurrentlyExpandedPosition) {
173affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee                // Hide actions, if the clicked item is the expanded item.
1742f05af35af03de67c1c474cd148719b24fac3552Andrew Lee                viewHolder.showActions(false);
175bae7b937b6cf6e7eb26d07bec95de38083923614Andrew Lee
176affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee                mCurrentlyExpandedPosition = RecyclerView.NO_POSITION;
177affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee                mCurrentlyExpandedRowId = NO_EXPANDED_LIST_ITEM;
178affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee            } else {
179cdc14da9275c67d123b55e668f48f73c4b58d948Sarmad Hashmi                if (viewHolder.callType == CallLog.Calls.MISSED_TYPE) {
180cdc14da9275c67d123b55e668f48f73c4b58d948Sarmad Hashmi                    CallLogAsyncTaskUtil.markCallAsRead(mContext, viewHolder.callIds);
1816b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi                    if (mActivityType == ACTIVITY_TYPE_DIALTACTS) {
182cb55981252b49e476e1adf9f2d5ec19a658d2aa4Sarmad Hashmi                        ((DialtactsActivity) v.getContext()).updateTabUnreadCounts();
183cb55981252b49e476e1adf9f2d5ec19a658d2aa4Sarmad Hashmi                    }
184cdc14da9275c67d123b55e668f48f73c4b58d948Sarmad Hashmi                }
185affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee                expandViewHolderActions(viewHolder);
186affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee            }
187affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee
188b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee        }
189b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee    };
19068e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn
191bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    /**
192bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * Click handler used to dismiss the promo card when the user taps the "ok" button.
193bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     */
194bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    private final View.OnClickListener mOkActionListener = new View.OnClickListener() {
195bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen        @Override
196bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen        public void onClick(View view) {
197bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen            dismissVoicemailPromoCard();
198bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen        }
199bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    };
200bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen
201bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    /**
202bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * Click handler used to send the user to the voicemail settings screen and then dismiss the
203bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * promo card.
204bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     */
205bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    private final View.OnClickListener mVoicemailSettingsActionListener =
206bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen            new View.OnClickListener() {
207bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen        @Override
208bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen        public void onClick(View view) {
209bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen            Intent intent = new Intent(TelephonyManager.ACTION_CONFIGURE_VOICEMAIL);
210bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen            mContext.startActivity(intent);
211bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen            dismissVoicemailPromoCard();
212bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen        }
213bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    };
214bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen
215affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee    private void expandViewHolderActions(CallLogListItemViewHolder viewHolder) {
216affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee        // If another item is expanded, notify it that it has changed. Its actions will be
217affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee        // hidden when it is re-binded because we change mCurrentlyExpandedPosition below.
218affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee        if (mCurrentlyExpandedPosition != RecyclerView.NO_POSITION) {
219affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee            notifyItemChanged(mCurrentlyExpandedPosition);
220affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee        }
221affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee        // Show the actions for the clicked list item.
2222f05af35af03de67c1c474cd148719b24fac3552Andrew Lee        viewHolder.showActions(true);
223affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee        mCurrentlyExpandedPosition = viewHolder.getAdapterPosition();
224affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee        mCurrentlyExpandedRowId = viewHolder.rowId;
225affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee    }
22674479d448bc39c3534585a627fba603aa89e93caAndrew Lee
227affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee    /**
228affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee     * Expand the actions on a list item when focused in Talkback mode, to aid discoverability.
229affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee     */
230b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee    private AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() {
231b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee        @Override
232c940eada912f952a95d693ae6aab48ef08ef7319Andrew Lee        public boolean onRequestSendAccessibilityEvent(
233c940eada912f952a95d693ae6aab48ef08ef7319Andrew Lee                ViewGroup host, View child, AccessibilityEvent event) {
234b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee            if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) {
235c940eada912f952a95d693ae6aab48ef08ef7319Andrew Lee                // Only expand if actions are not already expanded, because triggering the expand
236c940eada912f952a95d693ae6aab48ef08ef7319Andrew Lee                // function on clicks causes the action views to lose the focus indicator.
237c940eada912f952a95d693ae6aab48ef08ef7319Andrew Lee                CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder) host.getTag();
238cdd20a38dd669fea7de380fdc58fb526cb8d6581Nancy Chen                if (mCurrentlyExpandedPosition != viewHolder.getAdapterPosition()) {
239d9c364df22e3f75d029ec12185f44fedb1aeacb1Nancy Chen                    if (mVoicemailPlaybackPresenter != null) {
240d9c364df22e3f75d029ec12185f44fedb1aeacb1Nancy Chen                        // Always reset the voicemail playback state on expand.
241d9c364df22e3f75d029ec12185f44fedb1aeacb1Nancy Chen                        mVoicemailPlaybackPresenter.resetAll();
242d9c364df22e3f75d029ec12185f44fedb1aeacb1Nancy Chen                    }
243d9c364df22e3f75d029ec12185f44fedb1aeacb1Nancy Chen
244c940eada912f952a95d693ae6aab48ef08ef7319Andrew Lee                    expandViewHolderActions((CallLogListItemViewHolder) host.getTag());
245c940eada912f952a95d693ae6aab48ef08ef7319Andrew Lee                }
24668e771378889a479a80aac29a9ec2136b7ef27b6Tyler Gunn            }
247b359699a1dd96a4581a47b11ef2a85ec4a8a9433Yorke Lee            return super.onRequestSendAccessibilityEvent(host, child, event);
248146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
249146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    };
250146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
251affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee    protected final OnContactInfoChangedListener mOnContactInfoChangedListener =
252affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee            new OnContactInfoChangedListener() {
253affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee                @Override
254affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee                public void onContactInfoChanged() {
255affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee                    notifyDataSetChanged();
256affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee                }
257affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee            };
258affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee
259c6fde8d1b9a4e586ca65b82e9911089a9da14508Andrew Lee    public CallLogAdapter(
260c6fde8d1b9a4e586ca65b82e9911089a9da14508Andrew Lee            Context context,
261c6fde8d1b9a4e586ca65b82e9911089a9da14508Andrew Lee            CallFetcher callFetcher,
262c6fde8d1b9a4e586ca65b82e9911089a9da14508Andrew Lee            ContactInfoHelper contactInfoHelper,
263267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee            VoicemailPlaybackPresenter voicemailPlaybackPresenter,
2646b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi            int activityType) {
26594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        super(context);
26694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
26794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mContext = context;
26894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallFetcher = callFetcher;
26994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mContactInfoHelper = contactInfoHelper;
270267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee        mVoicemailPlaybackPresenter = voicemailPlaybackPresenter;
2710bb059d61f1e6648dee6f0a4cf8f02a6a7c26ce7Yorke Lee        if (mVoicemailPlaybackPresenter != null) {
2720bb059d61f1e6648dee6f0a4cf8f02a6a7c26ce7Yorke Lee            mVoicemailPlaybackPresenter.setOnVoicemailDeletedListener(this);
2730bb059d61f1e6648dee6f0a4cf8f02a6a7c26ce7Yorke Lee        }
2746b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi
2756b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi        mActivityType = activityType;
276b77bf5df2b866dd40e330b7c2dedee4a1d51fc78Sai Cheemalapati
27774479d448bc39c3534585a627fba603aa89e93caAndrew Lee        mContactInfoCache = new ContactInfoCache(
27874479d448bc39c3534585a627fba603aa89e93caAndrew Lee                mContactInfoHelper, mOnContactInfoChangedListener);
279c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Lee        if (!PermissionsUtil.hasContactsPermissions(context)) {
280c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Lee            mContactInfoCache.disableRequestProcessing();
281c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Lee        }
28294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
28394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        Resources resources = mContext.getResources();
28494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        CallTypeHelper callTypeHelper = new CallTypeHelper(resources);
28594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
28637aa2f3d402bdb233d3c922fcde4f9aa6a262d68Nancy Chen        mCallLogCache = CallLogCache.getCallLogCache(mContext);
28737aa2f3d402bdb233d3c922fcde4f9aa6a262d68Nancy Chen
288e80d62229bb11a92f0db8d4e4bac6533bbed9b66Nancy Chen        PhoneCallDetailsHelper phoneCallDetailsHelper =
28937aa2f3d402bdb233d3c922fcde4f9aa6a262d68Nancy Chen                new PhoneCallDetailsHelper(mContext, resources, mCallLogCache);
290d3f6a6c56dec7d47bae1121ed1030f67c26736feAndrew Lee        mCallLogListItemHelper =
29137aa2f3d402bdb233d3c922fcde4f9aa6a262d68Nancy Chen                new CallLogListItemHelper(phoneCallDetailsHelper, resources, mCallLogCache);
29294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallLogGroupBuilder = new CallLogGroupBuilder(this);
2939bd094118e920b732394c29657f26b062f3e916bAnne Rong        mFilteredNumberAsyncQueryHandler =
2949bd094118e920b732394c29657f26b062f3e916bAnne Rong                new FilteredNumberAsyncQueryHandler(mContext.getContentResolver());
295b980fc4386cdc24a605fc682d0fef0c5dc54c327Andrew Lee
296b980fc4386cdc24a605fc682d0fef0c5dc54c327Andrew Lee        mPrefs = PreferenceManager.getDefaultSharedPreferences(context);
2975f1c7dbf86603f534fbacdc96bab30d683913f4fBrandon Maxwell        mContactsPreferences = new ContactsPreferences(mContext);
298b980fc4386cdc24a605fc682d0fef0c5dc54c327Andrew Lee        maybeShowVoicemailPromoCard();
29994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
30094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
301267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee    public void onSaveInstanceState(Bundle outState) {
302267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee        outState.putInt(KEY_EXPANDED_POSITION, mCurrentlyExpandedPosition);
303267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee        outState.putLong(KEY_EXPANDED_ROW_ID, mCurrentlyExpandedRowId);
304267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee    }
305267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee
306267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee    public void onRestoreInstanceState(Bundle savedInstanceState) {
307267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee        if (savedInstanceState != null) {
308267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee            mCurrentlyExpandedPosition =
309267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee                    savedInstanceState.getInt(KEY_EXPANDED_POSITION, RecyclerView.NO_POSITION);
310267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee            mCurrentlyExpandedRowId =
311267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee                    savedInstanceState.getLong(KEY_EXPANDED_ROW_ID, NO_EXPANDED_LIST_ITEM);
312267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee        }
313267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee    }
314267e9ebd056ec4973c4b37c38f949e863de4f24cAndrew Lee
315486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa    @Override
316486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa    public void onBlockedNumber(String number,String countryIso) {
317486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa        String cacheKey = PhoneNumberUtils.formatNumberToE164(number, countryIso);
318486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa        if (!TextUtils.isEmpty(cacheKey)) {
319486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa            mBlockedNumberCache.put(cacheKey, true);
320486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa            notifyDataSetChanged();
321486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa        }
322486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa    }
323486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa
324486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa    @Override
325486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa    public void onUnblockedNumber( String number, String countryIso) {
326486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa        String cacheKey = PhoneNumberUtils.formatNumberToE164(number, countryIso);
327486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa        if (!TextUtils.isEmpty(cacheKey)) {
328486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa            mBlockedNumberCache.put(cacheKey, false);
329486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa            notifyDataSetChanged();
330486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa        }
331486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa    }
332486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa
33394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
33494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Requery on background thread when {@link Cursor} changes.
33594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
33694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
33794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    protected void onContentChanged() {
33894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallFetcher.fetchCalls();
33994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
34094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
341fb585079cc4c522c27f6dd6bf03fd296535960f3Yorke Lee    public void setLoading(boolean loading) {
34294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mLoading = loading;
34394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
34494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
34594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    public boolean isEmpty() {
34694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        if (mLoading) {
34794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            // We don't want the empty state to show when loading.
34894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            return false;
34994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        } else {
350492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee            return getItemCount() == 0;
35194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
35294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
35394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
35494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    public void invalidateCache() {
35574479d448bc39c3534585a627fba603aa89e93caAndrew Lee        mContactInfoCache.invalidate();
35694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
35794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
358b980fc4386cdc24a605fc682d0fef0c5dc54c327Andrew Lee    public void onResume() {
359142362f8253e7456640c14d6acaf1969afc4b68dYorke Lee        if (PermissionsUtil.hasPermission(mContext, android.Manifest.permission.READ_CONTACTS)) {
360142362f8253e7456640c14d6acaf1969afc4b68dYorke Lee            mContactInfoCache.start();
361142362f8253e7456640c14d6acaf1969afc4b68dYorke Lee        }
3625f1c7dbf86603f534fbacdc96bab30d683913f4fBrandon Maxwell        mContactsPreferences.refreshValue(ContactsPreferences.DISPLAY_ORDER_KEY);
363142362f8253e7456640c14d6acaf1969afc4b68dYorke Lee    }
364142362f8253e7456640c14d6acaf1969afc4b68dYorke Lee
3652d588b857347fda465a963742c4f61e4014f3441Nancy Chen    public void onPause() {
3662d588b857347fda465a963742c4f61e4014f3441Nancy Chen        pauseCache();
367b67294e72e074ee5b67c692f6674cee296fe8927Andrew Lee
3682d588b857347fda465a963742c4f61e4014f3441Nancy Chen        if (mHiddenItemUri != null) {
3692d588b857347fda465a963742c4f61e4014f3441Nancy Chen            CallLogAsyncTaskUtil.deleteVoicemail(mContext, mHiddenItemUri, null);
3702d588b857347fda465a963742c4f61e4014f3441Nancy Chen        }
3712d588b857347fda465a963742c4f61e4014f3441Nancy Chen    }
3722d588b857347fda465a963742c4f61e4014f3441Nancy Chen
3732d588b857347fda465a963742c4f61e4014f3441Nancy Chen    @VisibleForTesting
3742d588b857347fda465a963742c4f61e4014f3441Nancy Chen    /* package */ void pauseCache() {
37574479d448bc39c3534585a627fba603aa89e93caAndrew Lee        mContactInfoCache.stop();
37637aa2f3d402bdb233d3c922fcde4f9aa6a262d68Nancy Chen        mCallLogCache.reset();
37794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
37894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
37994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
38094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    protected void addGroups(Cursor cursor) {
38194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        mCallLogGroupBuilder.addGroups(cursor);
38294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
38394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
38494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @Override
3856b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi    public void addVoicemailGroups(Cursor cursor) {
3866b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi        mCallLogGroupBuilder.addVoicemailGroups(cursor);
3876b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi    }
3886b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi
3896b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi    @Override
390492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
391a4adb2c035690a1c9600a20c2485886d9d5991d0Andrew Lee        if (viewType == VIEW_TYPE_VOICEMAIL_PROMO_CARD) {
392bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen            return createVoicemailPromoCardViewHolder(parent);
39369705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee        }
3949afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn        return createCallLogEntryViewHolder(parent);
3959afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn    }
3969afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn
3979afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn    /**
3989afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn     * Creates a new call log entry {@link ViewHolder}.
3999afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn     *
4009afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn     * @param parent the parent view.
4019afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn     * @return The {@link ViewHolder}.
4029afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn     */
4039afa723dcebf18759c63dc1c976b05050e348d2aTyler Gunn    private ViewHolder createCallLogEntryViewHolder(ViewGroup parent) {
404492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee        LayoutInflater inflater = LayoutInflater.from(mContext);
4052ff08a8f8d4762ab5d0aebb0b69079f0b8d20b3eYorke Lee        View view = inflater.inflate(R.layout.call_log_list_item, parent, false);
406c1b7d0ae8cdfc0f0dddb5c2bb45c8239ffc6a264Andrew Lee        CallLogListItemViewHolder viewHolder = CallLogListItemViewHolder.create(
407c1b7d0ae8cdfc0f0dddb5c2bb45c8239ffc6a264Andrew Lee                view,
408c1b7d0ae8cdfc0f0dddb5c2bb45c8239ffc6a264Andrew Lee                mContext,
409486ee39d0791d290411290af6d2e54f37436b09fGilles Franck Mevaa                this,
410bae7b937b6cf6e7eb26d07bec95de38083923614Andrew Lee                mExpandCollapseListener,
41137aa2f3d402bdb233d3c922fcde4f9aa6a262d68Nancy Chen                mCallLogCache,
412d3f6a6c56dec7d47bae1121ed1030f67c26736feAndrew Lee                mCallLogListItemHelper,
4139bd094118e920b732394c29657f26b062f3e916bAnne Rong                mVoicemailPlaybackPresenter,
4148d0847ca13ca46730756e1d3a3dff3d7d27fd18bAndrew Lee                mFilteredNumberAsyncQueryHandler,
415d81cc6c64f3213f571c1f1e7a5c7e59b71491fb0Brandon Maxwell                new Callback() {
416d81cc6c64f3213f571c1f1e7a5c7e59b71491fb0Brandon Maxwell                    @Override
417d81cc6c64f3213f571c1f1e7a5c7e59b71491fb0Brandon Maxwell                    public void onFilterNumberSuccess() {
418d81cc6c64f3213f571c1f1e7a5c7e59b71491fb0Brandon Maxwell                        Logger.logInteraction(
419d81cc6c64f3213f571c1f1e7a5c7e59b71491fb0Brandon Maxwell                                InteractionEvent.BLOCK_NUMBER_CALL_LOG);
420d81cc6c64f3213f571c1f1e7a5c7e59b71491fb0Brandon Maxwell                    }
421d81cc6c64f3213f571c1f1e7a5c7e59b71491fb0Brandon Maxwell
422d81cc6c64f3213f571c1f1e7a5c7e59b71491fb0Brandon Maxwell                    @Override
423d81cc6c64f3213f571c1f1e7a5c7e59b71491fb0Brandon Maxwell                    public void onUnfilterNumberSuccess() {
424d81cc6c64f3213f571c1f1e7a5c7e59b71491fb0Brandon Maxwell                        Logger.logInteraction(
425d81cc6c64f3213f571c1f1e7a5c7e59b71491fb0Brandon Maxwell                                InteractionEvent.UNBLOCK_NUMBER_CALL_LOG);
426d81cc6c64f3213f571c1f1e7a5c7e59b71491fb0Brandon Maxwell                    }
427d81cc6c64f3213f571c1f1e7a5c7e59b71491fb0Brandon Maxwell
428d81cc6c64f3213f571c1f1e7a5c7e59b71491fb0Brandon Maxwell                    @Override
429d81cc6c64f3213f571c1f1e7a5c7e59b71491fb0Brandon Maxwell                    public void onChangeFilteredNumberUndo() {}
4306b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi                }, mActivityType == ACTIVITY_TYPE_ARCHIVE);
431affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee
432affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee        viewHolder.callLogEntryView.setTag(viewHolder);
433affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee        viewHolder.callLogEntryView.setAccessibilityDelegate(mAccessibilityDelegate);
434affe8b7947dd58edc3d9f4685a3bdde53f46762bAndrew Lee
435c1b7d0ae8cdfc0f0dddb5c2bb45c8239ffc6a264Andrew Lee        viewHolder.primaryActionView.setTag(viewHolder);
436c987e00fa84f8997c07e8cb2d413897ae1d41b14Andrew Lee
437c1b7d0ae8cdfc0f0dddb5c2bb45c8239ffc6a264Andrew Lee        return viewHolder;
43894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
43994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
44094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    /**
44194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Binds the views in the entry to the data in the call log.
442a9a82f52cbcadd0b9a4aafa0c785c0d6af629f1cSantos Cordon     * TODO: This gets called 20-30 times when Dialer starts up for a single call log entry and
443a9a82f52cbcadd0b9a4aafa0c785c0d6af629f1cSantos Cordon     * should not. It invokes cross-process methods and the repeat execution can get costly.
44494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     *
445a482522fb8fe4e9959c749f4ec616ae59cf06b28Brandon Maxwell     * @param viewHolder The view corresponding to this entry.
446bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * @param position The position of the entry.
44794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
448240523d3e1b4502326c8d0d313dd1787aa8ff024Victor Chang    @Override
449492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee    public void onBindViewHolder(ViewHolder viewHolder, int position) {
45049efd91e50a11dc7bdef8382a0ceac01bc060f77Andrew Lee        Trace.beginSection("onBindViewHolder: " + position);
451bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen
452bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen        switch (getItemViewType(position)) {
453bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen            case VIEW_TYPE_VOICEMAIL_PROMO_CARD:
454bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen                bindVoicemailPromoCardViewHolder(viewHolder);
455bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen                break;
456bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen            default:
457bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen                bindCallLogListViewHolder(viewHolder, position);
458bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen                break;
459bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen        }
460bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen
461bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen        Trace.endSection();
462bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    }
463bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen
464bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    /**
465bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * Binds the promo card view holder.
466bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     *
467bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * @param viewHolder The promo card view holder.
468bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     */
469bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    protected void bindVoicemailPromoCardViewHolder(ViewHolder viewHolder) {
470bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen        PromoCardViewHolder promoCardViewHolder = (PromoCardViewHolder) viewHolder;
471bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen
472ab90a18e2f05c7ae4158b770a9fbe9cbe4544597Andrew Lee        promoCardViewHolder.getSecondaryActionView()
473ab90a18e2f05c7ae4158b770a9fbe9cbe4544597Andrew Lee                .setOnClickListener(mVoicemailSettingsActionListener);
474ab90a18e2f05c7ae4158b770a9fbe9cbe4544597Andrew Lee        promoCardViewHolder.getPrimaryActionView().setOnClickListener(mOkActionListener);
475bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    }
476bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen
477bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    /**
478bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * Binds the view holder for the call log list item view.
479bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     *
480bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * @param viewHolder The call log list item view holder.
481bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * @param position The position of the list item.
482bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     */
483bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen
484bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    private void bindCallLogListViewHolder(ViewHolder viewHolder, int position) {
485492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee        Cursor c = (Cursor) getItem(position);
486492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee        if (c == null) {
487492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee            return;
488492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee        }
489bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen
490492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee        int count = getGroupSize(position);
491492cd7371c6d8fddc4de85887a4ed9a89d602767Andrew Lee
49294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        final String number = c.getString(CallLogQuery.NUMBER);
493a46ed83a7ccba16bbfd791a3a6588d5f0add9526Brad Ebinger        final String countryIso = c.getString(CallLogQuery.COUNTRY_ISO);
49417df9323e45ae5984b6df25b788a9cbffb51e8abBrandon Maxwell        final String postDialDigits = CompatUtils.isNCompatible()
4956b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi                && mActivityType != ACTIVITY_TYPE_ARCHIVE ?
4966b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi                c.getString(CallLogQuery.POST_DIAL_DIGITS) : "";
497a46ed83a7ccba16bbfd791a3a6588d5f0add9526Brad Ebinger        final String viaNumber = CompatUtils.isNCompatible()
498a46ed83a7ccba16bbfd791a3a6588d5f0add9526Brad Ebinger                && mActivityType != ACTIVITY_TYPE_ARCHIVE ?
499a46ed83a7ccba16bbfd791a3a6588d5f0add9526Brad Ebinger                c.getString(CallLogQuery.VIA_NUMBER) : "";
500719a7adde25e0a717816b00668c16c3a1e3c5518Jay Shrauner        final int numberPresentation = c.getInt(CallLogQuery.NUMBER_PRESENTATION);
501b2eebafbc1f1e26b5178b2858ca335467b4bc341Nancy Chen        final PhoneAccountHandle accountHandle = PhoneAccountUtils.getAccount(
502b2eebafbc1f1e26b5178b2858ca335467b4bc341Nancy Chen                c.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME),
503b2eebafbc1f1e26b5178b2858ca335467b4bc341Nancy Chen                c.getString(CallLogQuery.ACCOUNT_ID));
504a482522fb8fe4e9959c749f4ec616ae59cf06b28Brandon Maxwell        final ContactInfo cachedContactInfo = ContactInfoHelper.getContactInfo(c);
50556cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee        final boolean isVoicemailNumber =
50637aa2f3d402bdb233d3c922fcde4f9aa6a262d68Nancy Chen                mCallLogCache.isVoicemailNumber(accountHandle, number);
50756cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee
50814cfa66d6df53303c280194d661c0b32838aa417Andrew Lee        // Note: Binding of the action buttons is done as required in configureActionViews when the
50914cfa66d6df53303c280194d661c0b32838aa417Andrew Lee        // user expands the actions ViewStub.
510146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
51174479d448bc39c3534585a627fba603aa89e93caAndrew Lee        ContactInfo info = ContactInfo.EMPTY;
512d3f6a6c56dec7d47bae1121ed1030f67c26736feAndrew Lee        if (PhoneNumberUtil.canPlaceCallsTo(number, numberPresentation) && !isVoicemailNumber) {
51374479d448bc39c3534585a627fba603aa89e93caAndrew Lee            // Lookup contacts with this number
51435e44d4b757427a240e8764467bdd220e2124473Hall Liu            info = mContactInfoCache.getValue(number + postDialDigits,
51535e44d4b757427a240e8764467bdd220e2124473Hall Liu                    countryIso, cachedContactInfo);
51694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
5171e5325f43c98a92f8bfec1dbd9db3d32a91835e9Ihab Awad        CharSequence formattedNumber = info.formattedNumber == null
5188104b41f9ca85c2615e9aa52cb012b5868a0314fBrandon Maxwell                ? null : PhoneNumberUtilsCompat.createTtsSpannable(info.formattedNumber);
519edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee
520edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        final PhoneCallDetails details = new PhoneCallDetails(
52135e44d4b757427a240e8764467bdd220e2124473Hall Liu                mContext, number, numberPresentation, formattedNumber,
52235e44d4b757427a240e8764467bdd220e2124473Hall Liu                postDialDigits, isVoicemailNumber);
523a46ed83a7ccba16bbfd791a3a6588d5f0add9526Brad Ebinger        details.viaNumber = viaNumber;
524edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        details.accountHandle = accountHandle;
525edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        details.countryIso = countryIso;
526edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        details.date = c.getLong(CallLogQuery.DATE);
527edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        details.duration = c.getLong(CallLogQuery.DURATION);
528edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        details.features = getCallFeatures(c, count);
529edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        details.geocode = c.getString(CallLogQuery.GEOCODED_LOCATION);
530edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        details.transcription = c.getString(CallLogQuery.TRANSCRIPTION);
5316b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi        details.callTypes = getCallTypes(c, count);
532edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee
5338b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        if (!c.isNull(CallLogQuery.DATA_USAGE)) {
534edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee            details.dataUsage = c.getLong(CallLogQuery.DATA_USAGE);
5358b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        }
5368b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn
53736aeec91ed927b7fe3a27bcd5e224443899117f1Brandon Maxwell        if (!TextUtils.isEmpty(info.name) || !TextUtils.isEmpty(info.nameAlternative)) {
538edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee            details.contactUri = info.lookupUri;
53936aeec91ed927b7fe3a27bcd5e224443899117f1Brandon Maxwell            details.namePrimary = info.name;
54036aeec91ed927b7fe3a27bcd5e224443899117f1Brandon Maxwell            details.nameAlternative = info.nameAlternative;
54136aeec91ed927b7fe3a27bcd5e224443899117f1Brandon Maxwell            details.nameDisplayOrder = mContactsPreferences.getDisplayOrder();
542edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee            details.numberType = info.type;
543edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee            details.numberLabel = info.label;
544edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee            details.photoUri = info.photoUri;
545edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee            details.sourceType = info.sourceType;
5462f05af35af03de67c1c474cd148719b24fac3552Andrew Lee            details.objectId = info.objectId;
547240523d3e1b4502326c8d0d313dd1787aa8ff024Victor Chang            details.contactUserType = info.userType;
548edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        }
549704acc087ce359295475a46695c2821c55778344Chiao Cheng
55070bb286f79696fc3a3ee8a57a038a9f56087d902Andrew Lee        final CallLogListItemViewHolder views = (CallLogListItemViewHolder) viewHolder;
5515a9cd71b8ea670cd7c9aebd3dba27ea8cbe769dfAndrew Lee        views.info = info;
552edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        views.rowId = c.getLong(CallLogQuery.ID);
553edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        // Store values used when the actions ViewStub is inflated on expansion.
554edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        views.number = number;
55535e44d4b757427a240e8764467bdd220e2124473Hall Liu        views.postDialDigits = details.postDialDigits;
55618b4a2e3b8d60df39b3489c76bf4edffb81e15a5Tyler Gunn        views.displayNumber = details.displayNumber;
557edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        views.numberPresentation = numberPresentation;
5586b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi
559edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        views.accountHandle = accountHandle;
560edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        // Stash away the Ids of the calls so that we can support deleting a row in the call log.
561edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        views.callIds = getCallIds(c, count);
56218b4a2e3b8d60df39b3489c76bf4edffb81e15a5Tyler Gunn        views.isBusiness = mContactInfoHelper.isBusiness(info.sourceType);
56318b4a2e3b8d60df39b3489c76bf4edffb81e15a5Tyler Gunn        views.numberType = (String) Phone.getTypeLabel(mContext.getResources(), details.numberType,
56418b4a2e3b8d60df39b3489c76bf4edffb81e15a5Tyler Gunn                details.numberLabel);
565edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        // Default case: an item in the call log.
566edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        views.primaryActionView.setVisibility(View.VISIBLE);
567240523d3e1b4502326c8d0d313dd1787aa8ff024Victor Chang        views.workIconView.setVisibility(
568240523d3e1b4502326c8d0d313dd1787aa8ff024Victor Chang                details.contactUserType == ContactsUtils.USER_TYPE_WORK ? View.VISIBLE : View.GONE);
5699686330691f1216edff0ffa779138bda43388c47Sai Cheemalapati
570edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        // Check if the day group has changed and display a header if necessary.
571edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        int currentGroup = getDayGroupForCall(views.rowId);
572edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        int previousGroup = getPreviousDayGroup(c);
573edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        if (currentGroup != previousGroup) {
574edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee            views.dayGroupHeader.setVisibility(View.VISIBLE);
575edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee            views.dayGroupHeader.setText(getGroupDescription(currentGroup));
57694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        } else {
577edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee            views.dayGroupHeader.setVisibility(View.GONE);
57894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
57994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
5806b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi        if (mActivityType == ACTIVITY_TYPE_ARCHIVE) {
5816b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi            views.callType = CallLog.Calls.VOICEMAIL_TYPE;
5826b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi            views.voicemailUri = VoicemailArchiveContract.VoicemailArchive.buildWithId(c.getInt(
5836b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi                    c.getColumnIndex(VoicemailArchiveContract.VoicemailArchive._ID)))
5846b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi                    .toString();
5856b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi
5866b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi        } else {
5876b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi            if (details.callTypes[0] == CallLog.Calls.VOICEMAIL_TYPE ||
5886b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi                    details.callTypes[0] == CallLog.Calls.MISSED_TYPE) {
5896b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi                details.isRead = c.getInt(CallLogQuery.IS_READ) == 1;
5906b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi            }
5916b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi            views.callType = c.getInt(CallLogQuery.CALL_TYPE);
5926b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi            views.voicemailUri = c.getString(CallLogQuery.VOICEMAIL_URI);
5936b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi        }
5946b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi
595d3f6a6c56dec7d47bae1121ed1030f67c26736feAndrew Lee        mCallLogListItemHelper.setPhoneCallDetails(views, details);
596b0b57a10fbb9bec5c80d7adad8f65750a2f96e1bAndrew Lee
597edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        if (mCurrentlyExpandedRowId == views.rowId) {
598158dfa2dcb89db772f61af6f1f6775fcf5695e60Andrew Lee            // In case ViewHolders were added/removed, update the expanded position if the rowIds
599158dfa2dcb89db772f61af6f1f6775fcf5695e60Andrew Lee            // match so that we can restore the correct expanded state on rebind.
600158dfa2dcb89db772f61af6f1f6775fcf5695e60Andrew Lee            mCurrentlyExpandedPosition = position;
601fa15094f656599b24e1c2a5d59ca1d8c0e515d10Ta-wei Yen            views.showActions(true);
602fa15094f656599b24e1c2a5d59ca1d8c0e515d10Ta-wei Yen        } else {
603fa15094f656599b24e1c2a5d59ca1d8c0e515d10Ta-wei Yen            views.showActions(false);
604edb22da2b40549631a08150cbfc205e6ad243c20Andrew Lee        }
6057d38100ffecf97ba740df4ea2979550189922f46Ta-wei Yen        views.updatePhoto();
60656cb0efa5eda1670077e66fc0e8c79478d0c1c67Yorke Lee
607d3f6a6c56dec7d47bae1121ed1030f67c26736feAndrew Lee        mCallLogListItemHelper.setPhoneCallDetails(views, details);
608c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng    }
609c5b6a693d4773214ff8d3fcfa43d0a29581bb886Chiao Cheng
6105f1c7dbf86603f534fbacdc96bab30d683913f4fBrandon Maxwell    private String getPreferredDisplayName(ContactInfo contactInfo) {
6115f1c7dbf86603f534fbacdc96bab30d683913f4fBrandon Maxwell        if (mContactsPreferences.getDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_PRIMARY ||
6125f1c7dbf86603f534fbacdc96bab30d683913f4fBrandon Maxwell                TextUtils.isEmpty(contactInfo.nameAlternative)) {
6135f1c7dbf86603f534fbacdc96bab30d683913f4fBrandon Maxwell            return contactInfo.name;
6145f1c7dbf86603f534fbacdc96bab30d683913f4fBrandon Maxwell        }
6155f1c7dbf86603f534fbacdc96bab30d683913f4fBrandon Maxwell        return contactInfo.nameAlternative;
6165f1c7dbf86603f534fbacdc96bab30d683913f4fBrandon Maxwell    }
6175f1c7dbf86603f534fbacdc96bab30d683913f4fBrandon Maxwell
61869705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee    @Override
61969705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee    public int getItemCount() {
6202d588b857347fda465a963742c4f61e4014f3441Nancy Chen        return super.getItemCount() + (mShowVoicemailPromoCard ? 1 : 0)
6212d588b857347fda465a963742c4f61e4014f3441Nancy Chen                - (mHiddenPosition != RecyclerView.NO_POSITION ? 1 : 0);
62269705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee    }
62369705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee
62469705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee    @Override
62569705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee    public int getItemViewType(int position) {
626a4adb2c035690a1c9600a20c2485886d9d5991d0Andrew Lee        if (position == VOICEMAIL_PROMO_CARD_POSITION && mShowVoicemailPromoCard) {
627bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen            return VIEW_TYPE_VOICEMAIL_PROMO_CARD;
62869705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee        }
62969705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee        return super.getItemViewType(position);
63069705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee    }
63169705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee
632bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    /**
633bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * Retrieves an item at the specified position, taking into account the presence of a promo
634bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * card.
635bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     *
636bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * @param position The position to retrieve.
637bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * @return The item at that position.
638bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     */
639bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    @Override
640bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    public Object getItem(int position) {
6412d588b857347fda465a963742c4f61e4014f3441Nancy Chen        return super.getItem(position - (mShowVoicemailPromoCard ? 1 : 0)
6422d588b857347fda465a963742c4f61e4014f3441Nancy Chen                + ((mHiddenPosition != RecyclerView.NO_POSITION && position >= mHiddenPosition)
6436b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi                ? 1 : 0));
644bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    }
645bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen
6460599e880630892becf1a1991e6712e0e6d9df3c8Andrew Lee    @Override
6470599e880630892becf1a1991e6712e0e6d9df3c8Andrew Lee    public int getGroupSize(int position) {
6480599e880630892becf1a1991e6712e0e6d9df3c8Andrew Lee        return super.getGroupSize(position - (mShowVoicemailPromoCard ? 1 : 0));
6490599e880630892becf1a1991e6712e0e6d9df3c8Andrew Lee    }
6500599e880630892becf1a1991e6712e0e6d9df3c8Andrew Lee
651a4adb2c035690a1c9600a20c2485886d9d5991d0Andrew Lee    protected boolean isCallLogActivity() {
6526b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi        return mActivityType == ACTIVITY_TYPE_CALL_LOG;
65369705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee    }
65469705be50fc4c84b35df88c879dd9a4b4de655b3Andrew Lee
6552d588b857347fda465a963742c4f61e4014f3441Nancy Chen    /**
6562d588b857347fda465a963742c4f61e4014f3441Nancy Chen     * In order to implement the "undo" function, when a voicemail is "deleted" i.e. when the user
6572d588b857347fda465a963742c4f61e4014f3441Nancy Chen     * clicks the delete button, the deleted item is temporarily hidden from the list. If a user
6582d588b857347fda465a963742c4f61e4014f3441Nancy Chen     * clicks delete on a second item before the first item's undo option has expired, the first
6592d588b857347fda465a963742c4f61e4014f3441Nancy Chen     * item is immediately deleted so that only one item can be "undoed" at a time.
6602d588b857347fda465a963742c4f61e4014f3441Nancy Chen     */
6610bb059d61f1e6648dee6f0a4cf8f02a6a7c26ce7Yorke Lee    @Override
6620bb059d61f1e6648dee6f0a4cf8f02a6a7c26ce7Yorke Lee    public void onVoicemailDeleted(Uri uri) {
6632d588b857347fda465a963742c4f61e4014f3441Nancy Chen        if (mHiddenItemUri == null) {
6642d588b857347fda465a963742c4f61e4014f3441Nancy Chen            // Immediately hide the currently expanded card.
6652d588b857347fda465a963742c4f61e4014f3441Nancy Chen            mHiddenPosition = mCurrentlyExpandedPosition;
6662d588b857347fda465a963742c4f61e4014f3441Nancy Chen            notifyDataSetChanged();
6672d588b857347fda465a963742c4f61e4014f3441Nancy Chen        } else {
6682d588b857347fda465a963742c4f61e4014f3441Nancy Chen            // This means that there was a previous item that was hidden in the UI but not
6692d588b857347fda465a963742c4f61e4014f3441Nancy Chen            // yet deleted from the database (call it a "pending delete"). Delete this previous item
6702d588b857347fda465a963742c4f61e4014f3441Nancy Chen            // now since it is only possible to do one "undo" at a time.
6712d588b857347fda465a963742c4f61e4014f3441Nancy Chen            CallLogAsyncTaskUtil.deleteVoicemail(mContext, mHiddenItemUri, null);
6722d588b857347fda465a963742c4f61e4014f3441Nancy Chen
6732d588b857347fda465a963742c4f61e4014f3441Nancy Chen            // Set pending hide action so that the current item is hidden only after the previous
6742d588b857347fda465a963742c4f61e4014f3441Nancy Chen            // item is permanently deleted.
6752d588b857347fda465a963742c4f61e4014f3441Nancy Chen            mPendingHide = true;
6762d588b857347fda465a963742c4f61e4014f3441Nancy Chen        }
6772d588b857347fda465a963742c4f61e4014f3441Nancy Chen
6782d588b857347fda465a963742c4f61e4014f3441Nancy Chen        collapseExpandedCard();
6792d588b857347fda465a963742c4f61e4014f3441Nancy Chen
6802d588b857347fda465a963742c4f61e4014f3441Nancy Chen        // Save the new hidden item uri in case it needs to be deleted from the database when
6812d588b857347fda465a963742c4f61e4014f3441Nancy Chen        // a user attempts to delete another item.
6822d588b857347fda465a963742c4f61e4014f3441Nancy Chen        mHiddenItemUri = uri;
6832d588b857347fda465a963742c4f61e4014f3441Nancy Chen    }
6842d588b857347fda465a963742c4f61e4014f3441Nancy Chen
6852d588b857347fda465a963742c4f61e4014f3441Nancy Chen    private void collapseExpandedCard() {
6860bb059d61f1e6648dee6f0a4cf8f02a6a7c26ce7Yorke Lee        mCurrentlyExpandedRowId = NO_EXPANDED_LIST_ITEM;
6870bb059d61f1e6648dee6f0a4cf8f02a6a7c26ce7Yorke Lee        mCurrentlyExpandedPosition = RecyclerView.NO_POSITION;
6880bb059d61f1e6648dee6f0a4cf8f02a6a7c26ce7Yorke Lee    }
6890bb059d61f1e6648dee6f0a4cf8f02a6a7c26ce7Yorke Lee
690146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /**
691fa15094f656599b24e1c2a5d59ca1d8c0e515d10Ta-wei Yen     * When the list is changing all stored position is no longer valid.
692fa15094f656599b24e1c2a5d59ca1d8c0e515d10Ta-wei Yen     */
693fa15094f656599b24e1c2a5d59ca1d8c0e515d10Ta-wei Yen    public void invalidatePositions() {
694fa15094f656599b24e1c2a5d59ca1d8c0e515d10Ta-wei Yen        mCurrentlyExpandedPosition = RecyclerView.NO_POSITION;
695fa15094f656599b24e1c2a5d59ca1d8c0e515d10Ta-wei Yen        mHiddenPosition = RecyclerView.NO_POSITION;
696fa15094f656599b24e1c2a5d59ca1d8c0e515d10Ta-wei Yen    }
697fa15094f656599b24e1c2a5d59ca1d8c0e515d10Ta-wei Yen
698fa15094f656599b24e1c2a5d59ca1d8c0e515d10Ta-wei Yen    /**
6992d588b857347fda465a963742c4f61e4014f3441Nancy Chen     * When the user clicks "undo", the hidden item is unhidden.
7002d588b857347fda465a963742c4f61e4014f3441Nancy Chen     */
7012d588b857347fda465a963742c4f61e4014f3441Nancy Chen    @Override
7022d588b857347fda465a963742c4f61e4014f3441Nancy Chen    public void onVoicemailDeleteUndo() {
7032d588b857347fda465a963742c4f61e4014f3441Nancy Chen        mHiddenPosition = RecyclerView.NO_POSITION;
7042d588b857347fda465a963742c4f61e4014f3441Nancy Chen        mHiddenItemUri = null;
7052d588b857347fda465a963742c4f61e4014f3441Nancy Chen
7062d588b857347fda465a963742c4f61e4014f3441Nancy Chen        mPendingHide = false;
7072d588b857347fda465a963742c4f61e4014f3441Nancy Chen        notifyDataSetChanged();
7082d588b857347fda465a963742c4f61e4014f3441Nancy Chen    }
7092d588b857347fda465a963742c4f61e4014f3441Nancy Chen
7102d588b857347fda465a963742c4f61e4014f3441Nancy Chen    /**
7112d588b857347fda465a963742c4f61e4014f3441Nancy Chen     * This callback signifies that a database deletion has completed. This means that if there is
7122d588b857347fda465a963742c4f61e4014f3441Nancy Chen     * an item pending deletion, it will be hidden because the previous item that was in "undo" mode
7132d588b857347fda465a963742c4f61e4014f3441Nancy Chen     * has been removed from the database. Otherwise it simply resets the hidden state because there
7142d588b857347fda465a963742c4f61e4014f3441Nancy Chen     * are no pending deletes and thus no hidden items.
7152d588b857347fda465a963742c4f61e4014f3441Nancy Chen     */
7162d588b857347fda465a963742c4f61e4014f3441Nancy Chen    @Override
7172d588b857347fda465a963742c4f61e4014f3441Nancy Chen    public void onVoicemailDeletedInDatabase() {
7182d588b857347fda465a963742c4f61e4014f3441Nancy Chen        if (mPendingHide) {
7192d588b857347fda465a963742c4f61e4014f3441Nancy Chen            mHiddenPosition = mCurrentlyExpandedPosition;
7202d588b857347fda465a963742c4f61e4014f3441Nancy Chen            mPendingHide = false;
7212d588b857347fda465a963742c4f61e4014f3441Nancy Chen        } else {
7222d588b857347fda465a963742c4f61e4014f3441Nancy Chen            // There should no longer be any hidden item because it has been deleted from the
7232d588b857347fda465a963742c4f61e4014f3441Nancy Chen            // database.
7242d588b857347fda465a963742c4f61e4014f3441Nancy Chen            mHiddenPosition = RecyclerView.NO_POSITION;
7252d588b857347fda465a963742c4f61e4014f3441Nancy Chen            mHiddenItemUri = null;
7262d588b857347fda465a963742c4f61e4014f3441Nancy Chen        }
7272d588b857347fda465a963742c4f61e4014f3441Nancy Chen    }
7282d588b857347fda465a963742c4f61e4014f3441Nancy Chen
7292d588b857347fda465a963742c4f61e4014f3441Nancy Chen    /**
7304dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * Retrieves the day group of the previous call in the call log.  Used to determine if the day
7314dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * group has changed and to trigger display of the day group text.
7324dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *
7334dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @param cursor The call log cursor.
7344dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @return The previous day group, or DAY_GROUP_NONE if this is the first call.
7354dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     */
7364dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    private int getPreviousDayGroup(Cursor cursor) {
7374dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        // We want to restore the position in the cursor at the end.
7384dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        int startingPosition = cursor.getPosition();
7394dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        int dayGroup = CallLogGroupBuilder.DAY_GROUP_NONE;
7404dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        if (cursor.moveToPrevious()) {
7412d588b857347fda465a963742c4f61e4014f3441Nancy Chen            // If the previous entry is hidden (deleted in the UI but not in the database), skip it
7422d588b857347fda465a963742c4f61e4014f3441Nancy Chen            // and check the card above it. A list with the voicemail promo card at the top will be
7432d588b857347fda465a963742c4f61e4014f3441Nancy Chen            // 1-indexed because the 0th index is the promo card iteself.
7442d588b857347fda465a963742c4f61e4014f3441Nancy Chen            int previousViewPosition = mShowVoicemailPromoCard ? startingPosition :
7452d588b857347fda465a963742c4f61e4014f3441Nancy Chen                startingPosition - 1;
7462d588b857347fda465a963742c4f61e4014f3441Nancy Chen            if (previousViewPosition != mHiddenPosition ||
7472d588b857347fda465a963742c4f61e4014f3441Nancy Chen                    (previousViewPosition == mHiddenPosition && cursor.moveToPrevious())) {
7482d588b857347fda465a963742c4f61e4014f3441Nancy Chen                long previousRowId = cursor.getLong(CallLogQuery.ID);
7492d588b857347fda465a963742c4f61e4014f3441Nancy Chen                dayGroup = getDayGroupForCall(previousRowId);
7502d588b857347fda465a963742c4f61e4014f3441Nancy Chen            }
7514dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        }
7524dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        cursor.moveToPosition(startingPosition);
7534dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        return dayGroup;
7544dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    }
7554dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn
7564dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    /**
7574dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * Given a call Id, look up the day group that the call belongs to.  The day group data is
7584dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * populated in {@link com.android.dialer.calllog.CallLogGroupBuilder}.
7594dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *
7604dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @param callId The call to retrieve the day group for.
7614dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @return The day group for the call.
7624dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     */
7634dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    private int getDayGroupForCall(long callId) {
7644dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        if (mDayGroups.containsKey(callId)) {
7654dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            return mDayGroups.get(callId);
7664dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        }
7674dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        return CallLogGroupBuilder.DAY_GROUP_NONE;
7684dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    }
76981c3829f8a9377cb2e93c1fa6d223d223b78f371Andrew Lee
7704dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    /**
77194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Returns the call types for the given number of items in the cursor.
77294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
77394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * It uses the next {@code count} rows in the cursor to extract the types.
77494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * <p>
77594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * It position in the cursor is unchanged by this function.
77694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
77794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    private int[] getCallTypes(Cursor cursor, int count) {
7786b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi        if (mActivityType == ACTIVITY_TYPE_ARCHIVE) {
7796b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi            return new int[] {CallLog.Calls.VOICEMAIL_TYPE};
7806b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi        }
78194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        int position = cursor.getPosition();
78294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        int[] callTypes = new int[count];
78394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        for (int index = 0; index < count; ++index) {
78494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            callTypes[index] = cursor.getInt(CallLogQuery.CALL_TYPE);
78594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng            cursor.moveToNext();
78694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        }
78794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        cursor.moveToPosition(position);
78894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng        return callTypes;
78994b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
79094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
7918b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn    /**
7928b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     * Determine the features which were enabled for any of the calls that make up a call log
7938b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     * entry.
7948b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     *
7958b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     * @param cursor The cursor.
7968b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     * @param count The number of calls for the current call log entry.
7978b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     * @return The features.
7988b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn     */
7998b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn    private int getCallFeatures(Cursor cursor, int count) {
80003610993bf2adf12a6962c32851095551ffd0043Yorke Lee        int features = 0;
8018b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        int position = cursor.getPosition();
8028b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        for (int index = 0; index < count; ++index) {
8038b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn            features |= cursor.getInt(CallLogQuery.FEATURES);
8048b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn            cursor.moveToNext();
8058b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        }
8068b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        cursor.moveToPosition(position);
8078b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn        return features;
8088b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn    }
8098b0e858d5b4c50813dbe2b5c244e7013814b23ecTyler Gunn
810d0715acdfc1aee0c20950741dc15d30abd18d2f2Tyler Gunn    /**
81194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * Sets whether processing of requests for contact details should be enabled.
81274479d448bc39c3534585a627fba603aa89e93caAndrew Lee     *
81394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * This method should be called in tests to disable such processing of requests when not
81494b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     * needed.
81594b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng     */
81694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @VisibleForTesting
81794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    void disableRequestProcessingForTest() {
81874479d448bc39c3534585a627fba603aa89e93caAndrew Lee        // TODO: Remove this and test the cache directly.
819c16ea5ad67bf454158b364dec2f26c95a879c350Yorke Lee        mContactInfoCache.disableRequestProcessing();
82094b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
82194b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
82294b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    @VisibleForTesting
82394b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    void injectContactInfoForTest(String number, String countryIso, ContactInfo contactInfo) {
82474479d448bc39c3534585a627fba603aa89e93caAndrew Lee        // TODO: Remove this and test the cache directly.
82574479d448bc39c3534585a627fba603aa89e93caAndrew Lee        mContactInfoCache.injectContactInfoForTest(number, countryIso, contactInfo);
82694b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng    }
82794b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng
8284dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    /**
8294dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * Stores the day group associated with a call in the call log.
8304dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *
8314dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @param rowId The row Id of the current call.
8324dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @param dayGroup The day group the call belongs in.
8334dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     */
8344dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    @Override
8354dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    public void setDayGroup(long rowId, int dayGroup) {
8364dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        if (!mDayGroups.containsKey(rowId)) {
8374dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn            mDayGroups.put(rowId, dayGroup);
8384dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        }
8394dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    }
8404dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn
8414dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    /**
8424dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * Clears the day group associations on re-bind of the call log.
8434dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     */
8444dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    @Override
8454dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    public void clearDayGroups() {
8464dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn        mDayGroups.clear();
8474dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    }
8484dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn
849146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /**
850146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * Retrieves the call Ids represented by the current call log row.
851146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     *
852146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * @param cursor Call log cursor to retrieve call Ids from.
853146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * @param groupSize Number of calls associated with the current call log row.
854146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     * @return Array of call Ids.
855146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn     */
856cf5e001120916deb770ea65ae55730e456f92137Tyler Gunn    private long[] getCallIds(final Cursor cursor, final int groupSize) {
857146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // We want to restore the position in the cursor at the end.
858146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        int startingPosition = cursor.getPosition();
859146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        long[] ids = new long[groupSize];
860146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        // Copy the ids of the rows in the group.
861146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        for (int index = 0; index < groupSize; ++index) {
862146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            ids[index] = cursor.getLong(CallLogQuery.ID);
863146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn            cursor.moveToNext();
864146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        }
865146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        cursor.moveToPosition(startingPosition);
866146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn        return ids;
867146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    }
868146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn
869146a4cdf57f0d4d0cd85e808f1df2bdea639b24cTyler Gunn    /**
8704dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * Determines the description for a day group.
8714dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     *
8724dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @param group The day group to retrieve the description for.
8734dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     * @return The day group description.
8744dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn     */
8754dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    private CharSequence getGroupDescription(int group) {
8764dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn       if (group == CallLogGroupBuilder.DAY_GROUP_TODAY) {
8771e273313ff938ba0c7294dade433736d3fc5876bTyler Gunn           return mContext.getResources().getString(R.string.call_log_header_today);
8784dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn       } else if (group == CallLogGroupBuilder.DAY_GROUP_YESTERDAY) {
8791e273313ff938ba0c7294dade433736d3fc5876bTyler Gunn           return mContext.getResources().getString(R.string.call_log_header_yesterday);
8804dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn       } else {
8814dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn           return mContext.getResources().getString(R.string.call_log_header_other);
8824dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn       }
8834dfd7129ab04853504fe0c050e982db7b178b643Tyler Gunn    }
884bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen
885bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    /**
886bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * Determines if the voicemail promo card should be shown or not.  The voicemail promo card will
887bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * be shown as the first item in the voicemail tab.
888bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     */
889bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    private void maybeShowVoicemailPromoCard() {
890bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen        boolean showPromoCard = mPrefs.getBoolean(SHOW_VOICEMAIL_PROMO_CARD,
891bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen                SHOW_VOICEMAIL_PROMO_CARD_DEFAULT);
8926b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi        mShowVoicemailPromoCard = mActivityType != ACTIVITY_TYPE_ARCHIVE &&
8936b0056f348e1f9ecf0f91b53b51d240961bc8313Sarmad Hashmi                (mVoicemailPlaybackPresenter != null) && showPromoCard;
894bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    }
895bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen
896bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    /**
897bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * Dismisses the voicemail promo card and refreshes the call log.
898bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     */
899bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    private void dismissVoicemailPromoCard() {
900bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen        mPrefs.edit().putBoolean(SHOW_VOICEMAIL_PROMO_CARD, false).apply();
901a4adb2c035690a1c9600a20c2485886d9d5991d0Andrew Lee        mShowVoicemailPromoCard = false;
902bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen        notifyItemRemoved(VOICEMAIL_PROMO_CARD_POSITION);
903bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    }
904bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen
905bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    /**
906bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * Creates the view holder for the voicemail promo card.
907bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     *
908bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * @param parent The parent view.
909bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     * @return The {@link ViewHolder}.
910bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen     */
911bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    protected ViewHolder createVoicemailPromoCardViewHolder(ViewGroup parent) {
912bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen        LayoutInflater inflater = LayoutInflater.from(mContext);
913bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen        View view = inflater.inflate(R.layout.voicemail_promo_card, parent, false);
914bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen
915bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen        PromoCardViewHolder viewHolder = PromoCardViewHolder.create(view);
916bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen        return viewHolder;
917bdd2bc2efe22dc5b14cd2d3f5eb20350b69da875Nancy Chen    }
91894b10b530c0fc297e2974e57e094c500d3ee6003Chiao Cheng}
919