summaryrefslogtreecommitdiff
path: root/src/com/android/dialer/calllog/CallLogAdapter.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/dialer/calllog/CallLogAdapter.java')
-rw-r--r--src/com/android/dialer/calllog/CallLogAdapter.java959
1 files changed, 0 insertions, 959 deletions
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
deleted file mode 100644
index 9cde0b65d..000000000
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ /dev/null
@@ -1,959 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dialer.calllog;
-
-import com.android.dialer.filterednumber.BlockNumberDialogFragment;
-import com.android.dialer.service.ExtendedCallInfoService;
-import com.android.dialerbind.ObjectFactory;
-import com.google.common.annotations.VisibleForTesting;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Trace;
-import android.preference.PreferenceManager;
-import android.provider.CallLog;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.ViewHolder;
-import android.telecom.PhoneAccountHandle;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.AccessibilityDelegate;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-
-import com.android.contacts.common.ContactsUtils;
-import com.android.contacts.common.compat.CompatUtils;
-import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
-import com.android.contacts.common.preference.ContactsPreferences;
-import com.android.contacts.common.util.PermissionsUtil;
-import com.android.dialer.DialtactsActivity;
-import com.android.dialer.PhoneCallDetails;
-import com.android.dialer.R;
-import com.android.dialer.calllog.calllogcache.CallLogCache;
-import com.android.dialer.contactinfo.ContactInfoCache;
-import com.android.dialer.contactinfo.ContactInfoCache.OnContactInfoChangedListener;
-import com.android.dialer.database.FilteredNumberAsyncQueryHandler;
-import com.android.dialer.database.VoicemailArchiveContract;
-import com.android.dialer.logging.InteractionEvent;
-import com.android.dialer.logging.Logger;
-import com.android.dialer.util.PhoneNumberUtil;
-import com.android.dialer.voicemail.VoicemailPlaybackPresenter;
-
-import java.util.HashMap;
-
-/**
- * Adapter class to fill in data for the Call Log.
- */
-public class CallLogAdapter extends GroupingListAdapter
- implements CallLogGroupBuilder.GroupCreator,
- VoicemailPlaybackPresenter.OnVoicemailDeletedListener {
-
- // Types of activities the call log adapter is used for
- public static final int ACTIVITY_TYPE_CALL_LOG = 1;
- public static final int ACTIVITY_TYPE_ARCHIVE = 2;
- public static final int ACTIVITY_TYPE_DIALTACTS = 3;
-
- /** Interface used to initiate a refresh of the content. */
- public interface CallFetcher {
- public void fetchCalls();
- }
-
- private static final int NO_EXPANDED_LIST_ITEM = -1;
- // ConcurrentHashMap doesn't store null values. Use this value for numbers which aren't blocked.
- private static final int NOT_BLOCKED = -1;
-
- private static final int VOICEMAIL_PROMO_CARD_POSITION = 0;
-
- protected static final int VIEW_TYPE_NORMAL = 0;
- private static final int VIEW_TYPE_VOICEMAIL_PROMO_CARD = 1;
-
- /**
- * The key for the show voicemail promo card preference which will determine whether the promo
- * card was permanently dismissed or not.
- */
- private static final String SHOW_VOICEMAIL_PROMO_CARD = "show_voicemail_promo_card";
- private static final boolean SHOW_VOICEMAIL_PROMO_CARD_DEFAULT = true;
-
- protected final Context mContext;
- private final ContactInfoHelper mContactInfoHelper;
- protected final VoicemailPlaybackPresenter mVoicemailPlaybackPresenter;
- private final CallFetcher mCallFetcher;
- private final FilteredNumberAsyncQueryHandler mFilteredNumberAsyncQueryHandler;
-
- protected ContactInfoCache mContactInfoCache;
-
- private final int mActivityType;
-
- private static final String KEY_EXPANDED_POSITION = "expanded_position";
- private static final String KEY_EXPANDED_ROW_ID = "expanded_row_id";
-
- // Tracks the position of the currently expanded list item.
- private int mCurrentlyExpandedPosition = RecyclerView.NO_POSITION;
- // Tracks the rowId of the currently expanded list item, so the position can be updated if there
- // are any changes to the call log entries, such as additions or removals.
- private long mCurrentlyExpandedRowId = NO_EXPANDED_LIST_ITEM;
- private int mHiddenPosition = RecyclerView.NO_POSITION;
- private Uri mHiddenItemUri = null;
- private boolean mPendingHide = false;
- private BlockNumberDialogFragment.Callback mBlockedNumberDialogCallback =
- new BlockNumberDialogFragment.Callback() {
- @Override
- public void onFilterNumberSuccess() {
- Logger.logInteraction(
- InteractionEvent.BLOCK_NUMBER_CALL_LOG);
- notifyDataSetChanged();
- }
-
- @Override
- public void onUnfilterNumberSuccess() {
- Logger.logInteraction(
- InteractionEvent.UNBLOCK_NUMBER_CALL_LOG);
- notifyDataSetChanged();
- }
-
- @Override
- public void onChangeFilteredNumberUndo() {
- }
- };
- private CallLogListItemViewHolder.OnClickListener mBlockReportSpamListener;
-
- /**
- * Hashmap, keyed by call Id, used to track the day group for a call. As call log entries are
- * put into the primary call groups in {@link com.android.dialer.calllog.CallLogGroupBuilder},
- * they are also assigned a secondary "day group". This hashmap tracks the day group assigned
- * to all calls in the call log. This information is used to trigger the display of a day
- * group header above the call log entry at the start of a day group.
- * Note: Multiple calls are grouped into a single primary "call group" in the call log, and
- * the cursor used to bind rows includes all of these calls. When determining if a day group
- * change has occurred it is necessary to look at the last entry in the call log to determine
- * its day group. This hashmap provides a means of determining the previous day group without
- * having to reverse the cursor to the start of the previous day call log entry.
- */
- private HashMap<Long, Integer> mDayGroups = new HashMap<>();
-
- private boolean mLoading = true;
-
- private SharedPreferences mPrefs;
-
- private ContactsPreferences mContactsPreferences;
-
- protected boolean mShowVoicemailPromoCard = false;
-
- /** Instance of helper class for managing views. */
- private final CallLogListItemHelper mCallLogListItemHelper;
-
- /** Cache for repeated requests to Telecom/Telephony. */
- protected final CallLogCache mCallLogCache;
-
- /** Helper to group call log entries. */
- private final CallLogGroupBuilder mCallLogGroupBuilder;
-
- private ExtendedCallInfoService mExtendedCallInfoService;
-
- /**
- * The OnClickListener used to expand or collapse the action buttons of a call log entry.
- */
- private final View.OnClickListener mExpandCollapseListener = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder) v.getTag();
- if (viewHolder == null) {
- return;
- }
-
- if (mVoicemailPlaybackPresenter != null) {
- // Always reset the voicemail playback state on expand or collapse.
- mVoicemailPlaybackPresenter.resetAll();
- }
-
- if (viewHolder.getAdapterPosition() == mCurrentlyExpandedPosition) {
- // Hide actions, if the clicked item is the expanded item.
- viewHolder.showActions(false);
-
- mCurrentlyExpandedPosition = RecyclerView.NO_POSITION;
- mCurrentlyExpandedRowId = NO_EXPANDED_LIST_ITEM;
- } else {
- if (viewHolder.callType == CallLog.Calls.MISSED_TYPE) {
- CallLogAsyncTaskUtil.markCallAsRead(mContext, viewHolder.callIds);
- if (mActivityType == ACTIVITY_TYPE_DIALTACTS) {
- ((DialtactsActivity) v.getContext()).updateTabUnreadCounts();
- }
- }
- expandViewHolderActions(viewHolder);
- }
-
- }
- };
-
- /**
- * Click handler used to dismiss the promo card when the user taps the "ok" button.
- */
- private final View.OnClickListener mOkActionListener = new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- dismissVoicemailPromoCard();
- }
- };
-
- /**
- * Click handler used to send the user to the voicemail settings screen and then dismiss the
- * promo card.
- */
- private final View.OnClickListener mVoicemailSettingsActionListener =
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Intent intent = new Intent(TelephonyManager.ACTION_CONFIGURE_VOICEMAIL);
- mContext.startActivity(intent);
- dismissVoicemailPromoCard();
- }
- };
-
- private void expandViewHolderActions(CallLogListItemViewHolder viewHolder) {
- // If another item is expanded, notify it that it has changed. Its actions will be
- // hidden when it is re-binded because we change mCurrentlyExpandedPosition below.
- if (mCurrentlyExpandedPosition != RecyclerView.NO_POSITION) {
- notifyItemChanged(mCurrentlyExpandedPosition);
- }
- // Show the actions for the clicked list item.
- viewHolder.showActions(true);
- mCurrentlyExpandedPosition = viewHolder.getAdapterPosition();
- mCurrentlyExpandedRowId = viewHolder.rowId;
- }
-
- /**
- * Expand the actions on a list item when focused in Talkback mode, to aid discoverability.
- */
- private AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() {
- @Override
- public boolean onRequestSendAccessibilityEvent(
- ViewGroup host, View child, AccessibilityEvent event) {
- if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) {
- // Only expand if actions are not already expanded, because triggering the expand
- // function on clicks causes the action views to lose the focus indicator.
- CallLogListItemViewHolder viewHolder = (CallLogListItemViewHolder) host.getTag();
- if (mCurrentlyExpandedPosition != viewHolder.getAdapterPosition()) {
- if (mVoicemailPlaybackPresenter != null) {
- // Always reset the voicemail playback state on expand.
- mVoicemailPlaybackPresenter.resetAll();
- }
-
- expandViewHolderActions((CallLogListItemViewHolder) host.getTag());
- }
- }
- return super.onRequestSendAccessibilityEvent(host, child, event);
- }
- };
-
- protected final OnContactInfoChangedListener mOnContactInfoChangedListener =
- new OnContactInfoChangedListener() {
- @Override
- public void onContactInfoChanged() {
- notifyDataSetChanged();
- }
- };
-
- public CallLogAdapter(
- Context context,
- CallFetcher callFetcher,
- ContactInfoHelper contactInfoHelper,
- VoicemailPlaybackPresenter voicemailPlaybackPresenter,
- int activityType) {
- super(context);
-
- mContext = context;
- mCallFetcher = callFetcher;
- mContactInfoHelper = contactInfoHelper;
- mVoicemailPlaybackPresenter = voicemailPlaybackPresenter;
- if (mVoicemailPlaybackPresenter != null) {
- mVoicemailPlaybackPresenter.setOnVoicemailDeletedListener(this);
- }
-
- mActivityType = activityType;
-
- mContactInfoCache = new ContactInfoCache(
- mContactInfoHelper, mOnContactInfoChangedListener);
- if (!PermissionsUtil.hasContactsPermissions(context)) {
- mContactInfoCache.disableRequestProcessing();
- }
-
- Resources resources = mContext.getResources();
- CallTypeHelper callTypeHelper = new CallTypeHelper(resources);
-
- mCallLogCache = CallLogCache.getCallLogCache(mContext);
-
- PhoneCallDetailsHelper phoneCallDetailsHelper =
- new PhoneCallDetailsHelper(mContext, resources, mCallLogCache);
- mCallLogListItemHelper =
- new CallLogListItemHelper(phoneCallDetailsHelper, resources, mCallLogCache);
- mCallLogGroupBuilder = new CallLogGroupBuilder(this);
- mFilteredNumberAsyncQueryHandler =
- new FilteredNumberAsyncQueryHandler(mContext.getContentResolver());
-
- mPrefs = PreferenceManager.getDefaultSharedPreferences(context);
- mContactsPreferences = new ContactsPreferences(mContext);
- maybeShowVoicemailPromoCard();
-
- mExtendedCallInfoService = ObjectFactory.newExtendedCallInfoService(context);
- mBlockReportSpamListener = new BlockReportSpamListener(
- ((Activity) mContext).getFragmentManager(), this,
- mExtendedCallInfoService, mFilteredNumberAsyncQueryHandler);
- setHasStableIds(true);
- }
-
- public void onSaveInstanceState(Bundle outState) {
- outState.putInt(KEY_EXPANDED_POSITION, mCurrentlyExpandedPosition);
- outState.putLong(KEY_EXPANDED_ROW_ID, mCurrentlyExpandedRowId);
- }
-
- public void onRestoreInstanceState(Bundle savedInstanceState) {
- if (savedInstanceState != null) {
- mCurrentlyExpandedPosition =
- savedInstanceState.getInt(KEY_EXPANDED_POSITION, RecyclerView.NO_POSITION);
- mCurrentlyExpandedRowId =
- savedInstanceState.getLong(KEY_EXPANDED_ROW_ID, NO_EXPANDED_LIST_ITEM);
- }
- }
-
- /**
- * Requery on background thread when {@link Cursor} changes.
- */
- @Override
- protected void onContentChanged() {
- mCallFetcher.fetchCalls();
- }
-
- public void setLoading(boolean loading) {
- mLoading = loading;
- }
-
- public boolean isEmpty() {
- if (mLoading) {
- // We don't want the empty state to show when loading.
- return false;
- } else {
- return getItemCount() == 0;
- }
- }
-
- public void invalidateCache() {
- mContactInfoCache.invalidate();
- }
-
- public void onResume() {
- if (PermissionsUtil.hasPermission(mContext, android.Manifest.permission.READ_CONTACTS)) {
- mContactInfoCache.start();
- }
- mContactsPreferences.refreshValue(ContactsPreferences.DISPLAY_ORDER_KEY);
- }
-
- public void onPause() {
- pauseCache();
-
- if (mHiddenItemUri != null) {
- CallLogAsyncTaskUtil.deleteVoicemail(mContext, mHiddenItemUri, null);
- }
- }
-
- @VisibleForTesting
- /* package */ void pauseCache() {
- mContactInfoCache.stop();
- mCallLogCache.reset();
- }
-
- @Override
- protected void addGroups(Cursor cursor) {
- mCallLogGroupBuilder.addGroups(cursor);
- }
-
- @Override
- public void addVoicemailGroups(Cursor cursor) {
- mCallLogGroupBuilder.addVoicemailGroups(cursor);
- }
-
- @Override
- public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- if (viewType == VIEW_TYPE_VOICEMAIL_PROMO_CARD) {
- return createVoicemailPromoCardViewHolder(parent);
- }
- return createCallLogEntryViewHolder(parent);
- }
-
- /**
- * Creates a new call log entry {@link ViewHolder}.
- *
- * @param parent the parent view.
- * @return The {@link ViewHolder}.
- */
- private ViewHolder createCallLogEntryViewHolder(ViewGroup parent) {
- LayoutInflater inflater = LayoutInflater.from(mContext);
- View view = inflater.inflate(R.layout.call_log_list_item, parent, false);
- CallLogListItemViewHolder viewHolder = CallLogListItemViewHolder.create(
- view,
- mContext,
- mBlockReportSpamListener,
- mExpandCollapseListener,
- mCallLogCache,
- mCallLogListItemHelper,
- mVoicemailPlaybackPresenter,
- mFilteredNumberAsyncQueryHandler,
- mBlockedNumberDialogCallback,
- mActivityType == ACTIVITY_TYPE_ARCHIVE);
-
- viewHolder.callLogEntryView.setTag(viewHolder);
- viewHolder.callLogEntryView.setAccessibilityDelegate(mAccessibilityDelegate);
-
- viewHolder.primaryActionView.setTag(viewHolder);
-
- return viewHolder;
- }
-
- /**
- * Binds the views in the entry to the data in the call log.
- * TODO: This gets called 20-30 times when Dialer starts up for a single call log entry and
- * should not. It invokes cross-process methods and the repeat execution can get costly.
- *
- * @param viewHolder The view corresponding to this entry.
- * @param position The position of the entry.
- */
- @Override
- public void onBindViewHolder(ViewHolder viewHolder, int position) {
- Trace.beginSection("onBindViewHolder: " + position);
-
- switch (getItemViewType(position)) {
- case VIEW_TYPE_VOICEMAIL_PROMO_CARD:
- bindVoicemailPromoCardViewHolder(viewHolder);
- break;
- default:
- bindCallLogListViewHolder(viewHolder, position);
- break;
- }
-
- Trace.endSection();
- }
-
- /**
- * Binds the promo card view holder.
- *
- * @param viewHolder The promo card view holder.
- */
- protected void bindVoicemailPromoCardViewHolder(ViewHolder viewHolder) {
- PromoCardViewHolder promoCardViewHolder = (PromoCardViewHolder) viewHolder;
-
- promoCardViewHolder.getSecondaryActionView()
- .setOnClickListener(mVoicemailSettingsActionListener);
- promoCardViewHolder.getPrimaryActionView().setOnClickListener(mOkActionListener);
- }
-
- /**
- * Binds the view holder for the call log list item view.
- *
- * @param viewHolder The call log list item view holder.
- * @param position The position of the list item.
- */
-
- private void bindCallLogListViewHolder(final ViewHolder viewHolder, final int position) {
- Cursor c = (Cursor) getItem(position);
- if (c == null) {
- return;
- }
-
- final String number = c.getString(CallLogQuery.NUMBER);
- final String countryIso = c.getString(CallLogQuery.COUNTRY_ISO);
- final CallLogListItemViewHolder views = (CallLogListItemViewHolder) viewHolder;
- boolean success = mFilteredNumberAsyncQueryHandler.isBlockedNumber(
- new FilteredNumberAsyncQueryHandler.OnCheckBlockedListener() {
- @Override
- public void onCheckComplete(Integer id) {
- views.blockId = id;
- if (mExtendedCallInfoService == null) {
- loadDataAndRender(views);
- } else {
- views.isSpamFeatureEnabled = true;
- mExtendedCallInfoService.getExtendedCallInfo(number, countryIso,
- new ExtendedCallInfoService.Listener() {
- @Override
- public void onComplete(boolean isSpam) {
- views.isSpam = isSpam;
- loadDataAndRender(views);
- }
- });
- }
- }
- }, number, countryIso);
- if (!success) {
- loadDataAndRender(views);
- }
- }
-
- private void loadDataAndRender(CallLogListItemViewHolder views) {
- int position = views.getAdapterPosition();
- Cursor c = (Cursor) getItem(position);
- if (c == null) {
- return;
- }
-
- int count = getGroupSize(position);
-
- final String number = c.getString(CallLogQuery.NUMBER);
- final String countryIso = c.getString(CallLogQuery.COUNTRY_ISO);
- final String postDialDigits = CompatUtils.isNCompatible()
- && mActivityType != ACTIVITY_TYPE_ARCHIVE ?
- c.getString(CallLogQuery.POST_DIAL_DIGITS) : "";
- final String viaNumber = CompatUtils.isNCompatible()
- && mActivityType != ACTIVITY_TYPE_ARCHIVE ?
- c.getString(CallLogQuery.VIA_NUMBER) : "";
- final int numberPresentation = c.getInt(CallLogQuery.NUMBER_PRESENTATION);
- final PhoneAccountHandle accountHandle = PhoneAccountUtils.getAccount(
- c.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME),
- c.getString(CallLogQuery.ACCOUNT_ID));
- final ContactInfo cachedContactInfo = ContactInfoHelper.getContactInfo(c);
- final boolean isVoicemailNumber =
- mCallLogCache.isVoicemailNumber(accountHandle, number);
-
- // Note: Binding of the action buttons is done as required in configureActionViews when the
- // user expands the actions ViewStub.
-
- ContactInfo info = ContactInfo.EMPTY;
- if (PhoneNumberUtil.canPlaceCallsTo(number, numberPresentation) && !isVoicemailNumber) {
- // Lookup contacts with this number
- info = mContactInfoCache.getValue(number + postDialDigits,
- countryIso, cachedContactInfo);
- }
- CharSequence formattedNumber = info.formattedNumber == null
- ? null : PhoneNumberUtilsCompat.createTtsSpannable(info.formattedNumber);
-
- final PhoneCallDetails details = new PhoneCallDetails(
- mContext, number, numberPresentation, formattedNumber,
- postDialDigits, isVoicemailNumber);
- details.viaNumber = viaNumber;
- details.accountHandle = accountHandle;
- details.countryIso = countryIso;
- details.date = c.getLong(CallLogQuery.DATE);
- details.duration = c.getLong(CallLogQuery.DURATION);
- details.features = getCallFeatures(c, count);
- details.geocode = c.getString(CallLogQuery.GEOCODED_LOCATION);
- details.transcription = c.getString(CallLogQuery.TRANSCRIPTION);
- details.callTypes = getCallTypes(c, count);
-
- if (!c.isNull(CallLogQuery.DATA_USAGE)) {
- details.dataUsage = c.getLong(CallLogQuery.DATA_USAGE);
- }
-
- if (!TextUtils.isEmpty(info.name) || !TextUtils.isEmpty(info.nameAlternative)) {
- details.contactUri = info.lookupUri;
- details.namePrimary = info.name;
- details.nameAlternative = info.nameAlternative;
- details.nameDisplayOrder = mContactsPreferences.getDisplayOrder();
- details.numberType = info.type;
- details.numberLabel = info.label;
- details.photoUri = info.photoUri;
- details.sourceType = info.sourceType;
- details.objectId = info.objectId;
- details.contactUserType = info.userType;
- }
-
- views.info = info;
- views.rowId = c.getLong(CallLogQuery.ID);
- // Store values used when the actions ViewStub is inflated on expansion.
- views.number = number;
- views.postDialDigits = details.postDialDigits;
- views.displayNumber = details.displayNumber;
- views.numberPresentation = numberPresentation;
-
- views.accountHandle = accountHandle;
- // Stash away the Ids of the calls so that we can support deleting a row in the call log.
- views.callIds = getCallIds(c, count);
- views.isBusiness = mContactInfoHelper.isBusiness(info.sourceType);
- views.numberType = (String) Phone.getTypeLabel(mContext.getResources(), details.numberType,
- details.numberLabel);
- // Default case: an item in the call log.
- views.primaryActionView.setVisibility(View.VISIBLE);
- views.workIconView.setVisibility(
- details.contactUserType == ContactsUtils.USER_TYPE_WORK ? View.VISIBLE : View.GONE);
-
- // Check if the day group has changed and display a header if necessary.
- int currentGroup = getDayGroupForCall(views.rowId);
- int previousGroup = getPreviousDayGroup(c);
- if (currentGroup != previousGroup) {
- views.dayGroupHeader.setVisibility(View.VISIBLE);
- views.dayGroupHeader.setText(getGroupDescription(currentGroup));
- } else {
- views.dayGroupHeader.setVisibility(View.GONE);
- }
-
- if (mActivityType == ACTIVITY_TYPE_ARCHIVE) {
- views.callType = CallLog.Calls.VOICEMAIL_TYPE;
- views.voicemailUri = VoicemailArchiveContract.VoicemailArchive.buildWithId(c.getInt(
- c.getColumnIndex(VoicemailArchiveContract.VoicemailArchive._ID)))
- .toString();
-
- } else {
- if (details.callTypes[0] == CallLog.Calls.VOICEMAIL_TYPE ||
- details.callTypes[0] == CallLog.Calls.MISSED_TYPE) {
- details.isRead = c.getInt(CallLogQuery.IS_READ) == 1;
- }
- views.callType = c.getInt(CallLogQuery.CALL_TYPE);
- views.voicemailUri = c.getString(CallLogQuery.VOICEMAIL_URI);
- }
-
- // Reversely pass spam information from views since details is not constructed when spam
- // information comes back. This is used to render phone call details.
- details.isSpam = views.isSpam;
- render(views, details);
- }
-
- private void render(CallLogListItemViewHolder views, PhoneCallDetails details) {
- mCallLogListItemHelper.setPhoneCallDetails(views, details);
- if (mCurrentlyExpandedRowId == views.rowId) {
- // In case ViewHolders were added/removed, update the expanded position if the rowIds
- // match so that we can restore the correct expanded state on rebind.
- mCurrentlyExpandedPosition = views.getAdapterPosition();
- views.showActions(true);
- } else {
- views.showActions(false);
- }
- }
-
- private String getPreferredDisplayName(ContactInfo contactInfo) {
- if (mContactsPreferences.getDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_PRIMARY ||
- TextUtils.isEmpty(contactInfo.nameAlternative)) {
- return contactInfo.name;
- }
- return contactInfo.nameAlternative;
- }
-
- @Override
- public int getItemCount() {
- return super.getItemCount() + (mShowVoicemailPromoCard ? 1 : 0)
- - (mHiddenPosition != RecyclerView.NO_POSITION ? 1 : 0);
- }
-
- @Override
- public int getItemViewType(int position) {
- if (position == VOICEMAIL_PROMO_CARD_POSITION && mShowVoicemailPromoCard) {
- return VIEW_TYPE_VOICEMAIL_PROMO_CARD;
- }
- return super.getItemViewType(position);
- }
-
- /**
- * Retrieves an item at the specified position, taking into account the presence of a promo
- * card.
- *
- * @param position The position to retrieve.
- * @return The item at that position.
- */
- @Override
- public Object getItem(int position) {
- return super.getItem(position - (mShowVoicemailPromoCard ? 1 : 0)
- + ((mHiddenPosition != RecyclerView.NO_POSITION && position >= mHiddenPosition)
- ? 1 : 0));
- }
-
- @Override
- public long getItemId(int position) {
- Cursor cursor = (Cursor) getItem(position);
- if (cursor != null) {
- return cursor.getLong(CallLogQuery.ID);
- } else {
- return 0;
- }
- }
-
- @Override
- public int getGroupSize(int position) {
- return super.getGroupSize(position - (mShowVoicemailPromoCard ? 1 : 0));
- }
-
- protected boolean isCallLogActivity() {
- return mActivityType == ACTIVITY_TYPE_CALL_LOG;
- }
-
- /**
- * In order to implement the "undo" function, when a voicemail is "deleted" i.e. when the user
- * clicks the delete button, the deleted item is temporarily hidden from the list. If a user
- * clicks delete on a second item before the first item's undo option has expired, the first
- * item is immediately deleted so that only one item can be "undoed" at a time.
- */
- @Override
- public void onVoicemailDeleted(Uri uri) {
- if (mHiddenItemUri == null) {
- // Immediately hide the currently expanded card.
- mHiddenPosition = mCurrentlyExpandedPosition;
- notifyDataSetChanged();
- } else {
- // This means that there was a previous item that was hidden in the UI but not
- // yet deleted from the database (call it a "pending delete"). Delete this previous item
- // now since it is only possible to do one "undo" at a time.
- CallLogAsyncTaskUtil.deleteVoicemail(mContext, mHiddenItemUri, null);
-
- // Set pending hide action so that the current item is hidden only after the previous
- // item is permanently deleted.
- mPendingHide = true;
- }
-
- collapseExpandedCard();
-
- // Save the new hidden item uri in case it needs to be deleted from the database when
- // a user attempts to delete another item.
- mHiddenItemUri = uri;
- }
-
- private void collapseExpandedCard() {
- mCurrentlyExpandedRowId = NO_EXPANDED_LIST_ITEM;
- mCurrentlyExpandedPosition = RecyclerView.NO_POSITION;
- }
-
- /**
- * When the list is changing all stored position is no longer valid.
- */
- public void invalidatePositions() {
- mCurrentlyExpandedPosition = RecyclerView.NO_POSITION;
- mHiddenPosition = RecyclerView.NO_POSITION;
- }
-
- /**
- * When the user clicks "undo", the hidden item is unhidden.
- */
- @Override
- public void onVoicemailDeleteUndo() {
- mHiddenPosition = RecyclerView.NO_POSITION;
- mHiddenItemUri = null;
-
- mPendingHide = false;
- notifyDataSetChanged();
- }
-
- /**
- * This callback signifies that a database deletion has completed. This means that if there is
- * an item pending deletion, it will be hidden because the previous item that was in "undo" mode
- * has been removed from the database. Otherwise it simply resets the hidden state because there
- * are no pending deletes and thus no hidden items.
- */
- @Override
- public void onVoicemailDeletedInDatabase() {
- if (mPendingHide) {
- mHiddenPosition = mCurrentlyExpandedPosition;
- mPendingHide = false;
- } else {
- // There should no longer be any hidden item because it has been deleted from the
- // database.
- mHiddenPosition = RecyclerView.NO_POSITION;
- mHiddenItemUri = null;
- }
- }
-
- /**
- * Retrieves the day group of the previous call in the call log. Used to determine if the day
- * group has changed and to trigger display of the day group text.
- *
- * @param cursor The call log cursor.
- * @return The previous day group, or DAY_GROUP_NONE if this is the first call.
- */
- private int getPreviousDayGroup(Cursor cursor) {
- // We want to restore the position in the cursor at the end.
- int startingPosition = cursor.getPosition();
- int dayGroup = CallLogGroupBuilder.DAY_GROUP_NONE;
- if (cursor.moveToPrevious()) {
- // If the previous entry is hidden (deleted in the UI but not in the database), skip it
- // and check the card above it. A list with the voicemail promo card at the top will be
- // 1-indexed because the 0th index is the promo card iteself.
- int previousViewPosition = mShowVoicemailPromoCard ? startingPosition :
- startingPosition - 1;
- if (previousViewPosition != mHiddenPosition ||
- (previousViewPosition == mHiddenPosition && cursor.moveToPrevious())) {
- long previousRowId = cursor.getLong(CallLogQuery.ID);
- dayGroup = getDayGroupForCall(previousRowId);
- }
- }
- cursor.moveToPosition(startingPosition);
- return dayGroup;
- }
-
- /**
- * Given a call Id, look up the day group that the call belongs to. The day group data is
- * populated in {@link com.android.dialer.calllog.CallLogGroupBuilder}.
- *
- * @param callId The call to retrieve the day group for.
- * @return The day group for the call.
- */
- private int getDayGroupForCall(long callId) {
- if (mDayGroups.containsKey(callId)) {
- return mDayGroups.get(callId);
- }
- return CallLogGroupBuilder.DAY_GROUP_NONE;
- }
-
- /**
- * Returns the call types for the given number of items in the cursor.
- * <p>
- * It uses the next {@code count} rows in the cursor to extract the types.
- * <p>
- * It position in the cursor is unchanged by this function.
- */
- private int[] getCallTypes(Cursor cursor, int count) {
- if (mActivityType == ACTIVITY_TYPE_ARCHIVE) {
- return new int[] {CallLog.Calls.VOICEMAIL_TYPE};
- }
- int position = cursor.getPosition();
- int[] callTypes = new int[count];
- for (int index = 0; index < count; ++index) {
- callTypes[index] = cursor.getInt(CallLogQuery.CALL_TYPE);
- cursor.moveToNext();
- }
- cursor.moveToPosition(position);
- return callTypes;
- }
-
- /**
- * Determine the features which were enabled for any of the calls that make up a call log
- * entry.
- *
- * @param cursor The cursor.
- * @param count The number of calls for the current call log entry.
- * @return The features.
- */
- private int getCallFeatures(Cursor cursor, int count) {
- int features = 0;
- int position = cursor.getPosition();
- for (int index = 0; index < count; ++index) {
- features |= cursor.getInt(CallLogQuery.FEATURES);
- cursor.moveToNext();
- }
- cursor.moveToPosition(position);
- return features;
- }
-
- /**
- * Sets whether processing of requests for contact details should be enabled.
- *
- * This method should be called in tests to disable such processing of requests when not
- * needed.
- */
- @VisibleForTesting
- void disableRequestProcessingForTest() {
- // TODO: Remove this and test the cache directly.
- mContactInfoCache.disableRequestProcessing();
- }
-
- @VisibleForTesting
- void injectContactInfoForTest(String number, String countryIso, ContactInfo contactInfo) {
- // TODO: Remove this and test the cache directly.
- mContactInfoCache.injectContactInfoForTest(number, countryIso, contactInfo);
- }
-
- /**
- * Stores the day group associated with a call in the call log.
- *
- * @param rowId The row Id of the current call.
- * @param dayGroup The day group the call belongs in.
- */
- @Override
- public void setDayGroup(long rowId, int dayGroup) {
- if (!mDayGroups.containsKey(rowId)) {
- mDayGroups.put(rowId, dayGroup);
- }
- }
-
- /**
- * Clears the day group associations on re-bind of the call log.
- */
- @Override
- public void clearDayGroups() {
- mDayGroups.clear();
- }
-
- /**
- * Retrieves the call Ids represented by the current call log row.
- *
- * @param cursor Call log cursor to retrieve call Ids from.
- * @param groupSize Number of calls associated with the current call log row.
- * @return Array of call Ids.
- */
- private long[] getCallIds(final Cursor cursor, final int groupSize) {
- // We want to restore the position in the cursor at the end.
- int startingPosition = cursor.getPosition();
- long[] ids = new long[groupSize];
- // Copy the ids of the rows in the group.
- for (int index = 0; index < groupSize; ++index) {
- ids[index] = cursor.getLong(CallLogQuery.ID);
- cursor.moveToNext();
- }
- cursor.moveToPosition(startingPosition);
- return ids;
- }
-
- /**
- * Determines the description for a day group.
- *
- * @param group The day group to retrieve the description for.
- * @return The day group description.
- */
- private CharSequence getGroupDescription(int group) {
- if (group == CallLogGroupBuilder.DAY_GROUP_TODAY) {
- return mContext.getResources().getString(R.string.call_log_header_today);
- } else if (group == CallLogGroupBuilder.DAY_GROUP_YESTERDAY) {
- return mContext.getResources().getString(R.string.call_log_header_yesterday);
- } else {
- return mContext.getResources().getString(R.string.call_log_header_other);
- }
- }
-
- /**
- * Determines if the voicemail promo card should be shown or not. The voicemail promo card will
- * be shown as the first item in the voicemail tab.
- */
- private void maybeShowVoicemailPromoCard() {
- boolean showPromoCard = mPrefs.getBoolean(SHOW_VOICEMAIL_PROMO_CARD,
- SHOW_VOICEMAIL_PROMO_CARD_DEFAULT);
- mShowVoicemailPromoCard = mActivityType != ACTIVITY_TYPE_ARCHIVE &&
- (mVoicemailPlaybackPresenter != null) && showPromoCard;
- }
-
- /**
- * Dismisses the voicemail promo card and refreshes the call log.
- */
- private void dismissVoicemailPromoCard() {
- mPrefs.edit().putBoolean(SHOW_VOICEMAIL_PROMO_CARD, false).apply();
- mShowVoicemailPromoCard = false;
- notifyItemRemoved(VOICEMAIL_PROMO_CARD_POSITION);
- }
-
- /**
- * Creates the view holder for the voicemail promo card.
- *
- * @param parent The parent view.
- * @return The {@link ViewHolder}.
- */
- protected ViewHolder createVoicemailPromoCardViewHolder(ViewGroup parent) {
- LayoutInflater inflater = LayoutInflater.from(mContext);
- View view = inflater.inflate(R.layout.voicemail_promo_card, parent, false);
-
- PromoCardViewHolder viewHolder = PromoCardViewHolder.create(view);
- return viewHolder;
- }
-}