Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1eca06f5 authored by linyuh's avatar linyuh Committed by Copybara-Service
Browse files

Have Coalescer return CoalescedRow protos directly.

Bug: 77813585
Test: CoalescerTest, NewCallLogAdapterTest, NewCallLogViewHolderTest
PiperOrigin-RevId: 200086621
Change-Id: I8f79359a5972c578ae439aaf33233900b0606dc8
parent 1e4ef187
Loading
Loading
Loading
Loading
+59 −81
Original line number Diff line number Diff line
@@ -17,9 +17,9 @@ package com.android.dialer.calllog.database;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.provider.CallLog.Calls;
import android.support.annotation.NonNull;
import android.support.annotation.VisibleForTesting;
import android.support.annotation.WorkerThread;
import android.telecom.PhoneAccountHandle;
import android.text.TextUtils;
@@ -39,12 +39,12 @@ import com.android.dialer.metrics.Metrics;
import com.android.dialer.phonenumberproto.DialerPhoneNumberUtil;
import com.android.dialer.telecom.TelecomUtil;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.protobuf.InvalidProtocolBufferException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.inject.Inject;

@@ -56,24 +56,6 @@ import javax.inject.Inject;
 */
public class Coalescer {

  // Indexes for CoalescedAnnotatedCallLog.ALL_COLUMNS
  private static final int ID = 0;
  private static final int TIMESTAMP = 1;
  private static final int NUMBER = 2;
  private static final int FORMATTED_NUMBER = 3;
  private static final int NUMBER_PRESENTATION = 4;
  private static final int IS_READ = 5;
  private static final int NEW = 6;
  private static final int GEOCODED_LOCATION = 7;
  private static final int PHONE_ACCOUNT_COMPONENT_NAME = 8;
  private static final int PHONE_ACCOUNT_ID = 9;
  private static final int FEATURES = 10;
  private static final int NUMBER_ATTRIBUTES = 11;
  private static final int IS_VOICEMAIL_CALL = 12;
  private static final int VOICEMAIL_CALL_TAG = 13;
  private static final int CALL_TYPE = 14;
  private static final int COALESCED_IDS = 15;

  private final DataSources dataSources;
  private final FutureTimer futureTimer;
  private final ListeningExecutorService backgroundExecutorService;
@@ -94,12 +76,12 @@ public class Coalescer {
   *
   * @param allAnnotatedCallLogRowsSortedByTimestampDesc {@link AnnotatedCallLog} rows sorted in
   *     descending order of timestamp.
   * @return a future of a {@link MatrixCursor} containing the {@link CoalescedAnnotatedCallLog}
   *     rows to display
   * @return a future of a list of {@link CoalescedRow coalesced rows}, which will be used to
   *     display call log entries.
   */
  public ListenableFuture<Cursor> coalesce(
  public ListenableFuture<ImmutableList<CoalescedRow>> coalesce(
      @NonNull Cursor allAnnotatedCallLogRowsSortedByTimestampDesc) {
    ListenableFuture<Cursor> coalescingFuture =
    ListenableFuture<ImmutableList<CoalescedRow>> coalescingFuture =
        backgroundExecutorService.submit(
            () -> coalesceInternal(Assert.isNotNull(allAnnotatedCallLogRowsSortedByTimestampDesc)));
    futureTimer.applyTiming(coalescingFuture, Metrics.NEW_CALL_LOG_COALESCE);
@@ -108,34 +90,34 @@ public class Coalescer {

  /**
   * Reads the entire {@link AnnotatedCallLog} into memory from the provided cursor and then builds
   * and returns a new {@link MatrixCursor} of {@link CoalescedAnnotatedCallLog}, which is the
   * result of combining adjacent rows which should be collapsed for display purposes.
   * and returns a list of {@link CoalescedRow coalesced rows}, which is the result of combining
   * adjacent rows which should be collapsed for display purposes.
   *
   * @param allAnnotatedCallLogRowsSortedByTimestampDesc {@link AnnotatedCallLog} rows sorted in
   *     descending order of timestamp.
   * @return a new {@link MatrixCursor} containing the {@link CoalescedAnnotatedCallLog} rows to
   *     display
   * @return a list of {@link CoalescedRow coalesced rows}, which will be used to display call log
   *     entries.
   */
  @WorkerThread
  @NonNull
  private Cursor coalesceInternal(Cursor allAnnotatedCallLogRowsSortedByTimestampDesc) {
  private ImmutableList<CoalescedRow> coalesceInternal(
      Cursor allAnnotatedCallLogRowsSortedByTimestampDesc) {
    Assert.isWorkerThread();

    if (!allAnnotatedCallLogRowsSortedByTimestampDesc.moveToFirst()) {
      return ImmutableList.of();
    }

    // Note: This method relies on rowsShouldBeCombined to determine which rows should be combined,
    // but delegates to data sources to actually aggregate column values.

    DialerPhoneNumberUtil dialerPhoneNumberUtil = new DialerPhoneNumberUtil();

    MatrixCursor allCoalescedRowsMatrixCursor =
        new MatrixCursor(
            CoalescedAnnotatedCallLog.ALL_COLUMNS,
            allAnnotatedCallLogRowsSortedByTimestampDesc.getCount());

    if (!allAnnotatedCallLogRowsSortedByTimestampDesc.moveToFirst()) {
      return allCoalescedRowsMatrixCursor;
    }
    ImmutableList.Builder<CoalescedRow> coalescedRowListBuilder = new ImmutableList.Builder<>();

    int coalescedRowId = 0;

    // TODO(a bug): Avoid using ContentValues as it doesn't make sense here.
    List<ContentValues> currentRowGroup = new ArrayList<>();

    ContentValues firstRow = cursorRowToContentValues(allAnnotatedCallLogRowsSortedByTimestampDesc);
@@ -157,9 +139,10 @@ public class Coalescer {

      // Coalesce the group into a single row
      ContentValues coalescedRow = coalesceRowsForAllDataSources(currentRowGroup);
      coalescedRow.put(CoalescedAnnotatedCallLog._ID, coalescedRowId++);
      coalescedRow.put(
          CoalescedAnnotatedCallLog.COALESCED_IDS, getCoalescedIds(currentRowGroup).toByteArray());
      addContentValuesToMatrixCursor(coalescedRow, allCoalescedRowsMatrixCursor, coalescedRowId++);
      coalescedRowListBuilder.add(toCoalescedRowProto(coalescedRow));

      // Clear the current group after the rows are coalesced.
      currentRowGroup.clear();
@@ -170,7 +153,7 @@ public class Coalescer {
      }
    }

    return allCoalescedRowsMatrixCursor;
    return coalescedRowListBuilder.build();
  }

  private static ContentValues cursorRowToContentValues(Cursor cursor) {
@@ -293,34 +276,26 @@ public class Coalescer {
  }

  /**
   * @param contentValues a {@link CoalescedAnnotatedCallLog} row
   * @param matrixCursor represents {@link CoalescedAnnotatedCallLog}
   */
  private static void addContentValuesToMatrixCursor(
      ContentValues contentValues, MatrixCursor matrixCursor, int rowId) {
    MatrixCursor.RowBuilder rowBuilder = matrixCursor.newRow();
    rowBuilder.add(CoalescedAnnotatedCallLog._ID, rowId);
    for (Map.Entry<String, Object> entry : contentValues.valueSet()) {
      rowBuilder.add(entry.getKey(), entry.getValue());
    }
  }

  /**
   * Creates a new {@link CoalescedRow} based on the data at the provided cursor's current position.
   * Creates a new {@link CoalescedRow} proto based on the provided {@link ContentValues}.
   *
   * <p>The provided cursor should be one for {@link CoalescedAnnotatedCallLog}.
   * <p>The provided {@link ContentValues} should be one for {@link CoalescedAnnotatedCallLog}.
   */
  public static CoalescedRow toRow(Cursor coalescedAnnotatedCallLogCursor) {
  @VisibleForTesting
  static CoalescedRow toCoalescedRowProto(ContentValues coalescedContentValues) {
    DialerPhoneNumber number;
    try {
      number = DialerPhoneNumber.parseFrom(coalescedAnnotatedCallLogCursor.getBlob(NUMBER));
      number =
          DialerPhoneNumber.parseFrom(
              coalescedContentValues.getAsByteArray(CoalescedAnnotatedCallLog.NUMBER));
    } catch (InvalidProtocolBufferException e) {
      throw new IllegalStateException("Couldn't parse DialerPhoneNumber bytes");
    }

    CoalescedIds coalescedIds;
    try {
      coalescedIds = CoalescedIds.parseFrom(coalescedAnnotatedCallLogCursor.getBlob(COALESCED_IDS));
      coalescedIds =
          CoalescedIds.parseFrom(
              coalescedContentValues.getAsByteArray(CoalescedAnnotatedCallLog.COALESCED_IDS));
    } catch (InvalidProtocolBufferException e) {
      throw new IllegalStateException("Couldn't parse CoalescedIds bytes");
    }
@@ -328,61 +303,64 @@ public class Coalescer {
    NumberAttributes numberAttributes;
    try {
      numberAttributes =
          NumberAttributes.parseFrom(coalescedAnnotatedCallLogCursor.getBlob(NUMBER_ATTRIBUTES));
          NumberAttributes.parseFrom(
              coalescedContentValues.getAsByteArray(CoalescedAnnotatedCallLog.NUMBER_ATTRIBUTES));
    } catch (InvalidProtocolBufferException e) {
      throw new IllegalStateException("Couldn't parse NumberAttributes bytes");
    }

    CoalescedRow.Builder coalescedRowBuilder =
        CoalescedRow.newBuilder()
            .setId(coalescedAnnotatedCallLogCursor.getLong(ID))
            .setTimestamp(coalescedAnnotatedCallLogCursor.getLong(TIMESTAMP))
            .setId(coalescedContentValues.getAsLong(CoalescedAnnotatedCallLog._ID))
            .setTimestamp(coalescedContentValues.getAsLong(CoalescedAnnotatedCallLog.TIMESTAMP))
            .setNumber(number)
            .setNumberPresentation(coalescedAnnotatedCallLogCursor.getInt(NUMBER_PRESENTATION))
            .setIsRead(coalescedAnnotatedCallLogCursor.getInt(IS_READ) == 1)
            .setIsNew(coalescedAnnotatedCallLogCursor.getInt(NEW) == 1)
            .setFeatures(coalescedAnnotatedCallLogCursor.getInt(FEATURES))
            .setCallType(coalescedAnnotatedCallLogCursor.getInt(CALL_TYPE))
            .setNumberPresentation(
                coalescedContentValues.getAsInteger(CoalescedAnnotatedCallLog.NUMBER_PRESENTATION))
            .setIsRead(coalescedContentValues.getAsInteger(CoalescedAnnotatedCallLog.IS_READ) == 1)
            .setIsNew(coalescedContentValues.getAsInteger(CoalescedAnnotatedCallLog.NEW) == 1)
            .setFeatures(coalescedContentValues.getAsInteger(CoalescedAnnotatedCallLog.FEATURES))
            .setCallType(coalescedContentValues.getAsInteger(CoalescedAnnotatedCallLog.CALL_TYPE))
            .setNumberAttributes(numberAttributes)
            .setIsVoicemailCall(coalescedAnnotatedCallLogCursor.getInt(IS_VOICEMAIL_CALL) == 1)
            .setCoalescedIds(coalescedIds);

    String formattedNumber = coalescedAnnotatedCallLogCursor.getString(FORMATTED_NUMBER);
    // TODO(linyuh): none of the boolean columns in the annotated call log should be null.
    // This is a bug in VoicemailDataSource, but we should also fix the database constraints.
    Integer isVoicemailCall =
        coalescedContentValues.getAsInteger(CoalescedAnnotatedCallLog.IS_VOICEMAIL_CALL);
    coalescedRowBuilder.setIsVoicemailCall(isVoicemailCall != null && isVoicemailCall == 1);

    String formattedNumber =
        coalescedContentValues.getAsString(CoalescedAnnotatedCallLog.FORMATTED_NUMBER);
    if (!TextUtils.isEmpty(formattedNumber)) {
      coalescedRowBuilder.setFormattedNumber(formattedNumber);
    }

    String geocodedLocation = coalescedAnnotatedCallLogCursor.getString(GEOCODED_LOCATION);
    String geocodedLocation =
        coalescedContentValues.getAsString(CoalescedAnnotatedCallLog.GEOCODED_LOCATION);
    if (!TextUtils.isEmpty(geocodedLocation)) {
      coalescedRowBuilder.setGeocodedLocation(geocodedLocation);
    }

    String phoneAccountComponentName =
        coalescedAnnotatedCallLogCursor.getString(PHONE_ACCOUNT_COMPONENT_NAME);
        coalescedContentValues.getAsString(CoalescedAnnotatedCallLog.PHONE_ACCOUNT_COMPONENT_NAME);
    if (!TextUtils.isEmpty(phoneAccountComponentName)) {
      coalescedRowBuilder.setPhoneAccountComponentName(
          coalescedAnnotatedCallLogCursor.getString(PHONE_ACCOUNT_COMPONENT_NAME));
          coalescedContentValues.getAsString(
              CoalescedAnnotatedCallLog.PHONE_ACCOUNT_COMPONENT_NAME));
    }

    String phoneAccountId = coalescedAnnotatedCallLogCursor.getString(PHONE_ACCOUNT_ID);
    String phoneAccountId =
        coalescedContentValues.getAsString(CoalescedAnnotatedCallLog.PHONE_ACCOUNT_ID);
    if (!TextUtils.isEmpty(phoneAccountId)) {
      coalescedRowBuilder.setPhoneAccountId(phoneAccountId);
    }

    String voicemailCallTag = coalescedAnnotatedCallLogCursor.getString(VOICEMAIL_CALL_TAG);
    String voicemailCallTag =
        coalescedContentValues.getAsString(CoalescedAnnotatedCallLog.VOICEMAIL_CALL_TAG);
    if (!TextUtils.isEmpty(voicemailCallTag)) {
      coalescedRowBuilder.setVoicemailCallTag(voicemailCallTag);
    }

    return coalescedRowBuilder.build();
  }

  /**
   * Returns the timestamp at the provided cursor's current position.
   *
   * <p>The provided cursor should be one for {@link CoalescedAnnotatedCallLog}.
   */
  public static long getTimestamp(Cursor coalescedAnnotatedCallLogCursor) {
    return coalescedAnnotatedCallLogCursor.getLong(TIMESTAMP);
  }
}
+1 −43
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import android.os.Build;
import android.provider.BaseColumns;
import com.android.dialer.compat.android.provider.VoicemailCompat;
import com.android.dialer.constants.Constants;
import java.util.Arrays;

/** Contract for the AnnotatedCallLog content provider. */
public class AnnotatedCallLogContract {
@@ -29,11 +28,7 @@ public class AnnotatedCallLogContract {

  public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);

  /**
   * Columns shared by {@link AnnotatedCallLog} and {@link CoalescedAnnotatedCallLog}.
   *
   * <p>When adding columns be sure to update {@link #ALL_COMMON_COLUMNS}.
   */
  /** Columns shared by {@link AnnotatedCallLog} and {@link CoalescedAnnotatedCallLog}. */
  interface CommonColumns extends BaseColumns {

    /**
@@ -143,25 +138,6 @@ public class AnnotatedCallLogContract {
     * <p>Type: INTEGER (int)
     */
    String CALL_TYPE = "call_type";

    String[] ALL_COMMON_COLUMNS =
        new String[] {
          _ID,
          TIMESTAMP,
          NUMBER,
          FORMATTED_NUMBER,
          NUMBER_PRESENTATION,
          IS_READ,
          NEW,
          GEOCODED_LOCATION,
          PHONE_ACCOUNT_COMPONENT_NAME,
          PHONE_ACCOUNT_ID,
          FEATURES,
          NUMBER_ATTRIBUTES,
          IS_VOICEMAIL_CALL,
          VOICEMAIL_CALL_TAG,
          CALL_TYPE
        };
  }

  /**
@@ -239,8 +215,6 @@ public class AnnotatedCallLogContract {
   *
   * <p>This is an in-memory view of the {@link AnnotatedCallLog} with some adjacent entries
   * collapsed.
   *
   * <p>When adding columns be sure to update {@link #COLUMNS_ONLY_IN_COALESCED_CALL_LOG}.
   */
  public static final class CoalescedAnnotatedCallLog implements CommonColumns {

@@ -251,21 +225,5 @@ public class AnnotatedCallLogContract {
     * <p>Type: BLOB
     */
    public static final String COALESCED_IDS = "coalesced_ids";

    /**
     * Columns that are only in the {@link CoalescedAnnotatedCallLog} but not the {@link
     * AnnotatedCallLog}.
     */
    private static final String[] COLUMNS_ONLY_IN_COALESCED_CALL_LOG = new String[] {COALESCED_IDS};

    /** All columns in the {@link CoalescedAnnotatedCallLog}. */
    public static final String[] ALL_COLUMNS =
        concat(ALL_COMMON_COLUMNS, COLUMNS_ONLY_IN_COALESCED_CALL_LOG);
  }

  private static String[] concat(String[] first, String[] second) {
    String[] result = Arrays.copyOf(first, first.length + second.length);
    System.arraycopy(second, 0, result, first.length, second.length);
    return result;
  }
}
+23 −15
Original line number Diff line number Diff line
@@ -17,19 +17,19 @@ package com.android.dialer.calllog.ui;

import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import com.android.dialer.calllog.database.Coalescer;
import com.android.dialer.calllog.model.CoalescedRow;
import com.android.dialer.calllogutils.CallLogDates;
import com.android.dialer.common.Assert;
import com.android.dialer.logging.Logger;
import com.android.dialer.promotion.Promotion;
import com.android.dialer.time.Clock;
import com.google.common.collect.ImmutableList;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@@ -68,7 +68,7 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> {
  private final PopCounts popCounts = new PopCounts();
  @Nullable private final Promotion promotion;

  private Cursor cursor;
  private ImmutableList<CoalescedRow> coalescedRows;

  /** Position of the promotion card. Null when it should not be displayed. */
  @Nullable private Integer promotionCardPosition;
@@ -82,9 +82,13 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> {
  /** Position of the "Older" header. Null when it should not be displayed. */
  @Nullable private Integer olderHeaderPosition;

  NewCallLogAdapter(Activity activity, Cursor cursor, Clock clock, @Nullable Promotion promotion) {
  NewCallLogAdapter(
      Activity activity,
      ImmutableList<CoalescedRow> coalescedRows,
      Clock clock,
      @Nullable Promotion promotion) {
    this.activity = activity;
    this.cursor = cursor;
    this.coalescedRows = coalescedRows;
    this.clock = clock;
    this.realtimeRowProcessor = CallLogUiComponent.get(activity).realtimeRowProcessor();
    this.promotion = promotion;
@@ -92,8 +96,8 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> {
    setCardAndHeaderPositions();
  }

  void updateCursor(Cursor updatedCursor) {
    this.cursor = updatedCursor;
  void updateRows(ImmutableList<CoalescedRow> coalescedRows) {
    this.coalescedRows = coalescedRows;
    this.realtimeRowProcessor.clearCache();
    this.popCounts.reset();

@@ -119,7 +123,7 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> {
    }

    // If there are no rows to display, set all header positions to null.
    if (!cursor.moveToFirst()) {
    if (coalescedRows.isEmpty()) {
      todayHeaderPosition = null;
      yesterdayHeaderPosition = null;
      olderHeaderPosition = null;
@@ -131,17 +135,19 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> {

    int numItemsInToday = 0;
    int numItemsInYesterday = 0;
    do {
      long timestamp = Coalescer.getTimestamp(cursor);
    int numItemsInOlder = 0;
    for (CoalescedRow coalescedRow : coalescedRows) {
      long timestamp = coalescedRow.getTimestamp();
      long dayDifference = CallLogDates.getDayDifference(currentTimeMillis, timestamp);
      if (dayDifference == 0) {
        numItemsInToday++;
      } else if (dayDifference == 1) {
        numItemsInYesterday++;
      } else {
        numItemsInOlder = coalescedRows.size() - numItemsInToday - numItemsInYesterday;
        break;
      }
    } while (cursor.moveToNext());
    }

    if (numItemsInToday > 0) {
      numItemsInToday++; // including the "Today" header;
@@ -149,13 +155,16 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> {
    if (numItemsInYesterday > 0) {
      numItemsInYesterday++; // including the "Yesterday" header;
    }
    if (numItemsInOlder > 0) {
      numItemsInOlder++; // include the "Older" header;
    }

    // Set all header positions.
    // A header position will be null if there is no item to be displayed under that header.
    todayHeaderPosition = numItemsInToday > 0 ? numCards : null;
    yesterdayHeaderPosition = numItemsInYesterday > 0 ? numItemsInToday + numCards : null;
    olderHeaderPosition =
        !cursor.isAfterLast() ? numItemsInToday + numItemsInYesterday + numCards : null;
        numItemsInOlder > 0 ? numItemsInToday + numItemsInYesterday + numCards : null;
  }

  @Override
@@ -233,8 +242,7 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> {
        if (olderHeaderPosition != null && position > olderHeaderPosition) {
          previousCardAndHeaders++;
        }
        cursor.moveToPosition(position - previousCardAndHeaders);
        newCallLogViewHolder.bind(cursor);
        newCallLogViewHolder.bind(coalescedRows.get(position - previousCardAndHeaders));
        break;
      default:
        throw Assert.createIllegalStateFailException(
@@ -277,7 +285,7 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> {
    if (olderHeaderPosition != null) {
      numberOfHeaders++;
    }
    return cursor.getCount() + numberOfHeaders + numberOfCards;
    return coalescedRows.size() + numberOfHeaders + numberOfCards;
  }

  /**
+8 −6
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.view.ViewGroup;
import com.android.dialer.calllog.CallLogComponent;
import com.android.dialer.calllog.RefreshAnnotatedCallLogReceiver;
import com.android.dialer.calllog.database.CallLogDatabaseComponent;
import com.android.dialer.calllog.model.CoalescedRow;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.DefaultFutureCallback;
@@ -47,6 +48,7 @@ import com.android.dialer.promotion.PromotionComponent;
import com.android.dialer.util.PermissionsUtil;
import com.android.dialer.widget.EmptyContentView;
import com.android.dialer.widget.EmptyContentView.OnEmptyViewActionButtonClickedListener;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
@@ -65,7 +67,7 @@ public final class NewCallLogFragment extends Fragment implements LoaderCallback
  private RecyclerView recyclerView;
  private EmptyContentView emptyContentView;
  private RefreshAnnotatedCallLogReceiver refreshAnnotatedCallLogReceiver;
  private SupportUiListener<Cursor> coalesingAnnotatedCallLogListener;
  private SupportUiListener<ImmutableList<CoalescedRow>> coalesingAnnotatedCallLogListener;

  private boolean shouldMarkCallsRead = false;
  private final Runnable setShouldMarkCallsReadTrue = () -> shouldMarkCallsRead = true;
@@ -304,13 +306,13 @@ public final class NewCallLogFragment extends Fragment implements LoaderCallback

    // Start combining adjacent rows which should be collapsed for display purposes.
    // This is a time-consuming process so we will do it in the background.
    ListenableFuture<Cursor> coalescedCursorFuture =
    ListenableFuture<ImmutableList<CoalescedRow>> coalescedRowsFuture =
        CallLogDatabaseComponent.get(getContext()).coalescer().coalesce(newCursor);

    coalesingAnnotatedCallLogListener.listen(
        getContext(),
        coalescedCursorFuture,
        coalescedCursor -> {
        coalescedRowsFuture,
        coalescedRows -> {
          LogUtil.i("NewCallLogFragment.onLoadFinished", "coalescing succeeded");

          // TODO(zachh): Handle empty cursor by showing empty view.
@@ -323,14 +325,14 @@ public final class NewCallLogFragment extends Fragment implements LoaderCallback
            recyclerView.setAdapter(
                new NewCallLogAdapter(
                    activity,
                    coalescedCursor,
                    coalescedRows,
                    System::currentTimeMillis,
                    PromotionComponent.get(getContext())
                        .promotionManager()
                        .getHighestPriorityPromotion(PromotionType.CARD)
                        .orElse(null)));
          } else {
            ((NewCallLogAdapter) recyclerView.getAdapter()).updateCursor(coalescedCursor);
            ((NewCallLogAdapter) recyclerView.getAdapter()).updateRows(coalescedRows);
          }
        },
        throwable -> {
+7 −13
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@ package com.android.dialer.calllog.ui;

import android.app.Activity;
import android.content.res.ColorStateList;
import android.database.Cursor;
import android.provider.CallLog.Calls;
import android.support.annotation.ColorInt;
import android.support.annotation.DrawableRes;
@@ -31,7 +30,6 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.dialer.calllog.database.Coalescer;
import com.android.dialer.calllog.model.CoalescedRow;
import com.android.dialer.calllog.ui.NewCallLogAdapter.PopCounts;
import com.android.dialer.calllog.ui.menu.NewCallLogMenu;
@@ -101,25 +99,21 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder {
    uiExecutorService = DialerExecutorComponent.get(activity).uiExecutor();
  }

  /**
   * @param cursor a cursor for {@link
   *     com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.CoalescedAnnotatedCallLog}.
   */
  void bind(Cursor cursor) {
    CoalescedRow row = Coalescer.toRow(cursor);
    currentRowId = row.getId(); // Used to make sure async updates are applied to the correct views
  void bind(CoalescedRow coalescedRow) {
    // The row ID is used to make sure async updates are applied to the correct views.
    currentRowId = coalescedRow.getId();

    // Even if there is additional real time processing necessary, we still want to immediately show
    // what information we have, rather than an empty card. For example, if CP2 information needs to
    // be queried on the fly, we can still show the phone number until the contact name loads.
    displayRow(row);
    configA11yForRow(row);
    displayRow(coalescedRow);
    configA11yForRow(coalescedRow);

    // Note: This leaks the view holder via the callback (which is an inner class), but this is OK
    // because we only create ~10 of them (and they'll be collected assuming all jobs finish).
    Futures.addCallback(
        realtimeRowProcessor.applyRealtimeProcessing(row),
        new RealtimeRowFutureCallback(row),
        realtimeRowProcessor.applyRealtimeProcessing(coalescedRow),
        new RealtimeRowFutureCallback(coalescedRow),
        uiExecutorService);
  }