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

Commit 33d42e12 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes I933020d3,I27b6a630

* changes:
  Use PreCall.start instead of context.startActivity when starting calls from call log.
  Support extracting info from a Call in PhoneLookup
parents 4473e4b5 5f1d084c
Loading
Loading
Loading
Loading
+23 −23
Original line number Diff line number Diff line
@@ -15,8 +15,7 @@
 */
package com.android.dialer.calllog.ui;

import android.content.Context;
import android.content.Intent;
import android.app.Activity;
import android.content.res.ColorStateList;
import android.database.Cursor;
import android.provider.CallLog.Calls;
@@ -34,13 +33,14 @@ import com.android.dialer.calllog.model.CoalescedRow;
import com.android.dialer.calllog.ui.NewCallLogAdapter.PopCounts;
import com.android.dialer.calllog.ui.menu.NewCallLogMenu;
import com.android.dialer.calllogutils.CallLogEntryText;
import com.android.dialer.calllogutils.CallLogIntents;
import com.android.dialer.calllogutils.CallLogRowActions;
import com.android.dialer.calllogutils.NumberAttributesConverter;
import com.android.dialer.calllogutils.PhoneAccountUtils;
import com.android.dialer.common.concurrent.DialerExecutorComponent;
import com.android.dialer.compat.AppCompatConstants;
import com.android.dialer.compat.telephony.TelephonyManagerCompat;
import com.android.dialer.oem.MotorolaUtils;
import com.android.dialer.phonenumberutil.PhoneNumberHelper;
import com.android.dialer.telecom.TelecomUtil;
import com.android.dialer.time.Clock;
import com.android.dialer.widget.ContactPhotoView;
@@ -52,7 +52,7 @@ import java.util.concurrent.ExecutorService;
/** {@link RecyclerView.ViewHolder} for the new call log. */
final class NewCallLogViewHolder extends RecyclerView.ViewHolder {

  private final Context context;
  private final Activity activity;
  private final ContactPhotoView contactPhotoView;
  private final TextView primaryTextView;
  private final TextView callCountTextView;
@@ -74,7 +74,7 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder {
  NewCallLogViewHolder(
      View view, Clock clock, RealtimeRowProcessor realtimeRowProcessor, PopCounts popCounts) {
    super(view);
    this.context = view.getContext();
    this.activity = (Activity) view.getContext();
    contactPhotoView = view.findViewById(R.id.contact_photo_view);
    primaryTextView = view.findViewById(R.id.primary_text);
    callCountTextView = view.findViewById(R.id.call_count);
@@ -89,7 +89,7 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder {
    this.clock = clock;
    this.realtimeRowProcessor = realtimeRowProcessor;
    this.popCounts = popCounts;
    uiExecutorService = DialerExecutorComponent.get(context).uiExecutor();
    uiExecutorService = DialerExecutorComponent.get(activity).uiExecutor();
  }

  /** @param cursor a cursor from {@link CoalescedAnnotatedCallLogCursorLoader}. */
@@ -112,8 +112,8 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder {

  private void displayRow(CoalescedRow row) {
    // TODO(zachh): Handle RTL properly.
    primaryTextView.setText(CallLogEntryText.buildPrimaryText(context, row));
    secondaryTextView.setText(CallLogEntryText.buildSecondaryTextForEntries(context, clock, row));
    primaryTextView.setText(CallLogEntryText.buildPrimaryText(activity, row));
    secondaryTextView.setText(CallLogEntryText.buildSecondaryTextForEntries(activity, clock, row));

    if (isUnreadMissedCall(row)) {
      primaryTextView.setTextAppearance(R.style.primary_textview_unread_call);
@@ -168,7 +168,7 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder {
  private void setFeatureIcons(CoalescedRow row) {
    ColorStateList colorStateList =
        ColorStateList.valueOf(
            context.getColor(
            activity.getColor(
                isUnreadMissedCall(row)
                    ? R.color.feature_icon_unread_color
                    : R.color.feature_icon_read_color));
@@ -182,7 +182,7 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder {
    }

    // Handle Wifi Icon
    if (MotorolaUtils.shouldShowWifiIconInCallLog(context, row.getFeatures())) {
    if (MotorolaUtils.shouldShowWifiIconInCallLog(activity, row.getFeatures())) {
      wifiIcon.setVisibility(View.VISIBLE);
      wifiIcon.setImageTintList(colorStateList);
    } else {
@@ -229,10 +229,10 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder {

    if (isUnreadMissedCall(row)) {
      callTypeIcon.setImageTintList(
          ColorStateList.valueOf(context.getColor(R.color.call_type_icon_unread_color)));
          ColorStateList.valueOf(activity.getColor(R.color.call_type_icon_unread_color)));
    } else {
      callTypeIcon.setImageTintList(
          ColorStateList.valueOf(context.getColor(R.color.call_type_icon_read_color)));
          ColorStateList.valueOf(activity.getColor(R.color.call_type_icon_read_color)));
    }
  }

@@ -245,17 +245,19 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder {
      return;
    }

    String phoneAccountLabel = PhoneAccountUtils.getAccountLabel(context, phoneAccountHandle);
    String phoneAccountLabel = PhoneAccountUtils.getAccountLabel(activity, phoneAccountHandle);
    if (TextUtils.isEmpty(phoneAccountLabel)) {
      phoneAccountView.setVisibility(View.GONE);
      return;
    }

    @ColorInt
    int phoneAccountColor = PhoneAccountUtils.getAccountColor(context, phoneAccountHandle);
    int phoneAccountColor = PhoneAccountUtils.getAccountColor(activity, phoneAccountHandle);
    if (phoneAccountColor == PhoneAccount.NO_HIGHLIGHT_COLOR) {
      phoneAccountColor =
          context.getResources().getColor(R.color.dialer_secondary_text_color, context.getTheme());
          activity
              .getResources()
              .getColor(R.color.dialer_secondary_text_color, activity.getTheme());
    }

    phoneAccountView.setText(phoneAccountLabel);
@@ -264,17 +266,15 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder {
  }

  private void setOnClickListenerForRow(CoalescedRow row) {
    itemView.setOnClickListener(
        (view) -> {
          Intent callbackIntent = CallLogIntents.getCallBackIntent(context, row);
          if (callbackIntent != null) {
            context.startActivity(callbackIntent);
    if (!PhoneNumberHelper.canPlaceCallsTo(
        row.getNumber().getNormalizedNumber(), row.getNumberPresentation())) {
      return;
    }
        });
    itemView.setOnClickListener(view -> CallLogRowActions.startCallForRow(activity, row));
  }

  private void setOnClickListenerForMenuButon(CoalescedRow row) {
    menuButton.setOnClickListener(NewCallLogMenu.createOnClickListener(context, row));
    menuButton.setOnClickListener(NewCallLogMenu.createOnClickListener(activity, row));
  }

  private class RealtimeRowFutureCallback implements FutureCallback<CoalescedRow> {
+10 −20
Original line number Diff line number Diff line
@@ -15,39 +15,29 @@
 */
package com.android.dialer.calllogutils;

import android.content.Context;
import android.content.Intent;
import android.app.Activity;
import android.provider.CallLog.Calls;
import android.support.annotation.Nullable;
import com.android.dialer.callintent.CallInitiationType;
import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.calllog.model.CoalescedRow;
import com.android.dialer.phonenumberutil.PhoneNumberHelper;
import com.android.dialer.precall.PreCall;
import com.android.dialer.telecom.TelecomUtil;

/** Provides intents related to call log entries. */
public final class CallLogIntents {
/** Actions which can be performed on a call log row. */
public final class CallLogRowActions {

  /**
   * Returns an intent which can be used to call back for the provided row.
   * Places a call to the number in the provided {@link CoalescedRow}.
   *
   * <p>If the call was a video call, a video call will be placed, and if the call was an audio
   * call, an audio call will be placed.
   *
   * @return null if the provided {@code row} doesn't have a number
   * call, an audio call will be placed. The phone account corresponding to the row is used.
   */
  @Nullable
  public static Intent getCallBackIntent(Context context, CoalescedRow row) {
    String normalizedNumber = row.getNumber().getNormalizedNumber();
    if (!PhoneNumberHelper.canPlaceCallsTo(normalizedNumber, row.getNumberPresentation())) {
      return null;
    }

  public static void startCallForRow(Activity activity, CoalescedRow row) {
    // TODO(zachh): More granular logging?
    return PreCall.getIntent(
        context,
        new CallIntentBuilder(normalizedNumber, CallInitiationType.Type.CALL_LOG)
    PreCall.start(
        activity,
        new CallIntentBuilder(
                row.getNumber().getNormalizedNumber(), CallInitiationType.Type.CALL_LOG)
            .setPhoneAccountHandle(
                TelecomUtil.composePhoneAccountHandle(
                    row.getPhoneAccountComponentName(), row.getPhoneAccountId()))
+2 −1
Original line number Diff line number Diff line
@@ -66,7 +66,8 @@ public interface Metrics {
  String GET_MOST_RECENT_INFO_TEMPLATE = "%s.GetMostRecentInfo";
  String ON_SUCCESSFUL_FILL_TEMPLATE = "%s.OnSuccessfulFill";
  String ON_SUCCESSFUL_BULK_UPDATE_TEMPLATE = "%s.OnSuccessfulBulkUpdate";
  String LOOKUP_TEMPLATE = "%s.Lookup";
  String LOOKUP_FOR_CALL_TEMPLATE = "%s.LookupForCall";
  String LOOKUP_FOR_NUMBER_TEMPLATE = "%s.LookupForNumber";

  /** Start a timer. */
  void startTimer(String timerEventName);
+42 −0
Original line number Diff line number Diff line
@@ -16,11 +16,20 @@

package com.android.dialer.phonelookup;

import android.content.Context;
import android.support.annotation.MainThread;
import android.telecom.Call;
import com.android.dialer.DialerPhoneNumber;
import com.android.dialer.common.concurrent.DialerExecutorComponent;
import com.android.dialer.location.GeoUtil;
import com.android.dialer.phonenumberproto.DialerPhoneNumberUtil;
import com.android.dialer.telecom.TelecomCallUtil;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;

/**
 * Provides operations related to retrieving information about phone numbers.
@@ -31,12 +40,45 @@ import com.google.common.util.concurrent.ListenableFuture;
 */
public interface PhoneLookup<T> {

  /**
   * Returns a future containing a new info for the number associated with the provided call.
   *
   * <p>The returned message should contain populated data for the sub-message corresponding to this
   * {@link PhoneLookup}. For example, the CP2 implementation returns a {@link
   * PhoneLookupInfo.Cp2Info} sub-message.
   *
   * <p>The default implementation is for all {@link PhoneLookup} implementations that don't need
   * info in the given call, i.e., it simply extracts the phone number from the call and delegates
   * to {@link #lookup(DialerPhoneNumber)}.
   *
   * <p>However, for {@link PhoneLookup} implementations that need info in the call (such as one for
   * CNAP), they should override this method.
   */
  default ListenableFuture<T> lookup(Context appContext, Call call) {
    ListeningExecutorService backgroundExecutor =
        DialerExecutorComponent.get(appContext).backgroundExecutor();

    ListenableFuture<DialerPhoneNumber> numberFuture =
        backgroundExecutor.submit(
            () -> {
              DialerPhoneNumberUtil dialerPhoneNumberUtil = new DialerPhoneNumberUtil();
              return dialerPhoneNumberUtil.parse(
                  TelecomCallUtil.getNumber(call), GeoUtil.getCurrentCountryIso(appContext));
            });

    return Futures.transformAsync(numberFuture, this::lookup, MoreExecutors.directExecutor());
  }

  /**
   * Returns a future containing a new info for the provided number.
   *
   * <p>The returned message should contain populated data for the sub-message corresponding to this
   * {@link PhoneLookup}. For example, the CP2 implementation returns a {@link
   * PhoneLookupInfo.Cp2Info} sub-message.
   *
   * <p>If the lookup can't be done without info in a {@link Call} (e.g., CNAP), this method is
   * expected to return existing info saved during the most recent lookup for a call to/from the
   * provided number ({@link #lookup(Context, Call)}).
   */
  ListenableFuture<T> lookup(DialerPhoneNumber dialerPhoneNumber);

+54 −16
Original line number Diff line number Diff line
@@ -16,13 +16,16 @@

package com.android.dialer.phonelookup.composite;

import android.content.Context;
import android.support.annotation.MainThread;
import android.support.annotation.VisibleForTesting;
import android.telecom.Call;
import com.android.dialer.DialerPhoneNumber;
import com.android.dialer.calllog.CallLogState;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.Annotations.LightweightExecutor;
import com.android.dialer.common.concurrent.DialerFutures;
import com.android.dialer.inject.ApplicationContext;
import com.android.dialer.metrics.FutureTimer;
import com.android.dialer.metrics.FutureTimer.LogCatMode;
import com.android.dialer.metrics.Metrics;
@@ -51,6 +54,7 @@ import javax.inject.Inject;
 */
public final class CompositePhoneLookup {

  private final Context appContext;
  private final ImmutableList<PhoneLookup> phoneLookups;
  private final FutureTimer futureTimer;
  private final CallLogState callLogState;
@@ -59,10 +63,12 @@ public final class CompositePhoneLookup {
  @VisibleForTesting
  @Inject
  public CompositePhoneLookup(
      @ApplicationContext Context appContext,
      ImmutableList<PhoneLookup> phoneLookups,
      FutureTimer futureTimer,
      CallLogState callLogState,
      @LightweightExecutor ListeningExecutorService lightweightExecutorService) {
    this.appContext = appContext;
    this.phoneLookups = phoneLookups;
    this.futureTimer = futureTimer;
    this.callLogState = callLogState;
@@ -70,12 +76,37 @@ public final class CompositePhoneLookup {
  }

  /**
   * Delegates to a set of dependent lookups to build a complete {@link PhoneLookupInfo}.
   * Delegates to a set of dependent lookups to build a complete {@link PhoneLookupInfo} for the
   * number associated with the provided call.
   *
   * <p>Note: If any of the dependent lookups fails, the returned future will also fail. If any of
   * the dependent lookups does not complete, the returned future will also not complete.
   */
  public ListenableFuture<PhoneLookupInfo> lookup(Call call) {
    // TODO(zachh): Add short-circuiting logic so that this call is not blocked on low-priority
    // lookups finishing when a higher-priority one has already finished.
    List<ListenableFuture<?>> futures = new ArrayList<>();
    for (PhoneLookup<?> phoneLookup : phoneLookups) {
      ListenableFuture<?> lookupFuture = phoneLookup.lookup(appContext, call);
      String eventName =
          String.format(Metrics.LOOKUP_FOR_CALL_TEMPLATE, phoneLookup.getClass().getSimpleName());
      futureTimer.applyTiming(lookupFuture, eventName);
      futures.add(lookupFuture);
    }
    ListenableFuture<PhoneLookupInfo> combinedFuture = combineSubMessageFutures(futures);
    String eventName =
        String.format(Metrics.LOOKUP_FOR_CALL_TEMPLATE, CompositePhoneLookup.class.getSimpleName());
    futureTimer.applyTiming(combinedFuture, eventName);
    return combinedFuture;
  }

  /**
   * Delegates to a set of dependent lookups to build a complete {@link PhoneLookupInfo} for the
   * provided number.
   *
   * <p>Note: If any of the dependent lookups fails, the returned future will also fail. If any of
   * the dependent lookups does not complete, the returned future will also not complete.
   */
  @SuppressWarnings({"unchecked", "rawtype"})
  public ListenableFuture<PhoneLookupInfo> lookup(DialerPhoneNumber dialerPhoneNumber) {
    // TODO(zachh): Add short-circuiting logic so that this call is not blocked on low-priority
    // lookups finishing when a higher-priority one has already finished.
@@ -83,26 +114,33 @@ public final class CompositePhoneLookup {
    for (PhoneLookup<?> phoneLookup : phoneLookups) {
      ListenableFuture<?> lookupFuture = phoneLookup.lookup(dialerPhoneNumber);
      String eventName =
          String.format(Metrics.LOOKUP_TEMPLATE, phoneLookup.getClass().getSimpleName());
          String.format(Metrics.LOOKUP_FOR_NUMBER_TEMPLATE, phoneLookup.getClass().getSimpleName());
      futureTimer.applyTiming(lookupFuture, eventName);
      futures.add(lookupFuture);
    }
    ListenableFuture<PhoneLookupInfo> combinedFuture =
        Futures.transform(
            Futures.allAsList(futures),
            infos -> {
    ListenableFuture<PhoneLookupInfo> combinedFuture = combineSubMessageFutures(futures);
    String eventName =
        String.format(
            Metrics.LOOKUP_FOR_NUMBER_TEMPLATE, CompositePhoneLookup.class.getSimpleName());
    futureTimer.applyTiming(combinedFuture, eventName);
    return combinedFuture;
  }

  /** Combines a list of sub-message futures into a future for {@link PhoneLookupInfo}. */
  @SuppressWarnings({"unchecked", "rawtype"})
  private ListenableFuture<PhoneLookupInfo> combineSubMessageFutures(
      List<ListenableFuture<?>> subMessageFutures) {
    return Futures.transform(
        Futures.allAsList(subMessageFutures),
        subMessages -> {
          Builder mergedInfo = PhoneLookupInfo.newBuilder();
              for (int i = 0; i < infos.size(); i++) {
          for (int i = 0; i < subMessages.size(); i++) {
            PhoneLookup phoneLookup = phoneLookups.get(i);
                phoneLookup.setSubMessage(mergedInfo, infos.get(i));
            phoneLookup.setSubMessage(mergedInfo, subMessages.get(i));
          }
          return mergedInfo.build();
        },
        lightweightExecutorService);
    String eventName =
        String.format(Metrics.LOOKUP_TEMPLATE, CompositePhoneLookup.class.getSimpleName());
    futureTimer.applyTiming(combinedFuture, eventName);
    return combinedFuture;
  }

  /**
Loading