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

Commit 5ab679c5 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Have Coalescer return CoalescedRow protos directly."

parents 962e3e23 1eca06f5
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);
  }