Merge changes I277fcbc7,Idcf29c93 am: 92fb805602 am: 6c0a406956
am: 517572cd4d

Change-Id: I88ca15c86095328a9cef8a38f9fc16b6bcc4aba8
diff --git a/java/com/android/dialer/calllog/ui/menu/DeleteCallLogItemModule.java b/java/com/android/dialer/calllog/ui/menu/DeleteCallLogItemModule.java
index ad5671e..a929961 100644
--- a/java/com/android/dialer/calllog/ui/menu/DeleteCallLogItemModule.java
+++ b/java/com/android/dialer/calllog/ui/menu/DeleteCallLogItemModule.java
@@ -29,18 +29,20 @@
 import com.android.dialer.common.concurrent.DialerExecutorComponent;
 import com.android.dialer.common.database.Selection;
 import com.android.dialer.historyitemactions.HistoryItemActionModule;
+import com.android.dialer.logging.DialerImpression;
+import com.android.dialer.logging.Logger;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
 
 /** {@link HistoryItemActionModule} for deleting a call log item in the new call log. */
-public final class DeleteCallLogItemModule implements HistoryItemActionModule {
+final class DeleteCallLogItemModule implements HistoryItemActionModule {
   private static final String TAG = DeleteCallLogItemModule.class.getName();
 
   private final Context context;
   private final CoalescedIds coalescedIds;
 
-  public DeleteCallLogItemModule(Context context, CoalescedIds coalescedIds) {
+  DeleteCallLogItemModule(Context context, CoalescedIds coalescedIds) {
     this.context = context;
     this.coalescedIds = coalescedIds;
   }
@@ -62,6 +64,8 @@
         .createNonUiTaskBuilder(new CallLogItemDeletionWorker(context))
         .build()
         .executeSerial(coalescedIds);
+
+    Logger.get(context).logImpression(DialerImpression.Type.USER_DELETED_CALL_LOG_ITEM);
     return true;
   }
 
diff --git a/java/com/android/dialer/historyitemactions/BlockReportSpamModules.java b/java/com/android/dialer/historyitemactions/BlockReportSpamModules.java
index 396c033..c47b097 100644
--- a/java/com/android/dialer/historyitemactions/BlockReportSpamModules.java
+++ b/java/com/android/dialer/historyitemactions/BlockReportSpamModules.java
@@ -19,6 +19,9 @@
 import android.content.Context;
 import com.android.dialer.blockreportspam.BlockReportSpamDialogInfo;
 import com.android.dialer.blockreportspam.ShowBlockReportSpamDialogNotifier;
+import com.android.dialer.logging.DialerImpression;
+import com.android.dialer.logging.Logger;
+import java.util.Optional;
 
 /** Modules for blocking/unblocking a number and/or reporting it as spam/not spam. */
 final class BlockReportSpamModules {
@@ -26,7 +29,9 @@
   private BlockReportSpamModules() {}
 
   static HistoryItemActionModule moduleForMarkingNumberAsNotSpam(
-      Context context, BlockReportSpamDialogInfo blockReportSpamDialogInfo) {
+      Context context,
+      BlockReportSpamDialogInfo blockReportSpamDialogInfo,
+      Optional<DialerImpression.Type> impression) {
 
     return new HistoryItemActionModule() {
       @Override
@@ -43,13 +48,17 @@
       public boolean onClick() {
         ShowBlockReportSpamDialogNotifier.notifyShowDialogToReportNotSpam(
             context, blockReportSpamDialogInfo);
+
+        impression.ifPresent(Logger.get(context)::logImpression);
         return true; // Close the bottom sheet.
       }
     };
   }
 
   static HistoryItemActionModule moduleForBlockingNumber(
-      Context context, BlockReportSpamDialogInfo blockReportSpamDialogInfo) {
+      Context context,
+      BlockReportSpamDialogInfo blockReportSpamDialogInfo,
+      Optional<DialerImpression.Type> impression) {
 
     return new HistoryItemActionModule() {
       @Override
@@ -66,13 +75,17 @@
       public boolean onClick() {
         ShowBlockReportSpamDialogNotifier.notifyShowDialogToBlockNumber(
             context, blockReportSpamDialogInfo);
+
+        impression.ifPresent(Logger.get(context)::logImpression);
         return true; // Close the bottom sheet.
       }
     };
   }
 
   static HistoryItemActionModule moduleForUnblockingNumber(
-      Context context, BlockReportSpamDialogInfo blockReportSpamDialogInfo) {
+      Context context,
+      BlockReportSpamDialogInfo blockReportSpamDialogInfo,
+      Optional<DialerImpression.Type> impression) {
 
     return new HistoryItemActionModule() {
       @Override
@@ -90,13 +103,16 @@
         ShowBlockReportSpamDialogNotifier.notifyShowDialogToUnblockNumber(
             context, blockReportSpamDialogInfo);
 
+        impression.ifPresent(Logger.get(context)::logImpression);
         return true; // Close the bottom sheet.
       }
     };
   }
 
   static HistoryItemActionModule moduleForBlockingNumberAndOptionallyReportingSpam(
-      Context context, BlockReportSpamDialogInfo blockReportSpamDialogInfo) {
+      Context context,
+      BlockReportSpamDialogInfo blockReportSpamDialogInfo,
+      Optional<DialerImpression.Type> impression) {
 
     return new HistoryItemActionModule() {
       @Override
@@ -113,6 +129,8 @@
       public boolean onClick() {
         ShowBlockReportSpamDialogNotifier.notifyShowDialogToBlockNumberAndOptionallyReportSpam(
             context, blockReportSpamDialogInfo);
+
+        impression.ifPresent(Logger.get(context)::logImpression);
         return true; // Close the bottom sheet.
       }
     };
diff --git a/java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java b/java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java
index 0e78d70..917aa95 100644
--- a/java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java
+++ b/java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java
@@ -21,6 +21,7 @@
 import android.net.Uri;
 import android.provider.CallLog.Calls;
 import android.provider.ContactsContract;
+import android.support.annotation.IntDef;
 import android.text.TextUtils;
 import com.android.dialer.blockreportspam.BlockReportSpamDialogInfo;
 import com.android.dialer.callintent.CallInitiationType;
@@ -29,13 +30,19 @@
 import com.android.dialer.common.Assert;
 import com.android.dialer.duo.Duo;
 import com.android.dialer.duo.DuoComponent;
+import com.android.dialer.logging.DialerImpression;
 import com.android.dialer.logging.ReportingLocation;
 import com.android.dialer.spam.Spam;
 import com.android.dialer.util.CallUtil;
 import com.android.dialer.util.PermissionsUtil;
 import com.android.dialer.util.UriUtils;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 
 /**
  * Builds a list of {@link HistoryItemActionModule HistoryItemActionModules}.
@@ -76,6 +83,54 @@
  */
 public final class HistoryItemActionModulesBuilder {
 
+  /** Represents events when a module is tapped by the user. */
+  @Retention(RetentionPolicy.SOURCE)
+  @IntDef({
+    Event.ADD_TO_CONTACT,
+    Event.BLOCK_NUMBER,
+    Event.BLOCK_NUMBER_AND_REPORT_SPAM,
+    Event.REPORT_NOT_SPAM,
+    Event.REQUEST_CARRIER_VIDEO_CALL,
+    Event.REQUEST_DUO_VIDEO_CALL,
+    Event.REQUEST_DUO_VIDEO_CALL_FOR_NON_CONTACT,
+    Event.SEND_TEXT_MESSAGE,
+    Event.UNBLOCK_NUMBER
+  })
+  @interface Event {
+    int ADD_TO_CONTACT = 1;
+    int BLOCK_NUMBER = 2;
+    int BLOCK_NUMBER_AND_REPORT_SPAM = 3;
+    int REPORT_NOT_SPAM = 4;
+    int REQUEST_CARRIER_VIDEO_CALL = 5;
+    int REQUEST_DUO_VIDEO_CALL = 6;
+    int REQUEST_DUO_VIDEO_CALL_FOR_NON_CONTACT = 7;
+    int SEND_TEXT_MESSAGE = 8;
+    int UNBLOCK_NUMBER = 9;
+  }
+
+  /**
+   * Maps each {@link Event} to a {@link DialerImpression.Type} to be logged when the modules are
+   * hosted by the call log.
+   */
+  private static final ImmutableMap<Integer, DialerImpression.Type> CALL_LOG_IMPRESSIONS =
+      new ImmutableMap.Builder<Integer, DialerImpression.Type>()
+          .put(Event.ADD_TO_CONTACT, DialerImpression.Type.ADD_TO_A_CONTACT_FROM_CALL_LOG)
+          .put(Event.BLOCK_NUMBER, DialerImpression.Type.CALL_LOG_BLOCK_NUMBER)
+          .put(Event.BLOCK_NUMBER_AND_REPORT_SPAM, DialerImpression.Type.CALL_LOG_BLOCK_REPORT_SPAM)
+          .put(Event.REPORT_NOT_SPAM, DialerImpression.Type.CALL_LOG_REPORT_AS_NOT_SPAM)
+          .put(
+              Event.REQUEST_CARRIER_VIDEO_CALL,
+              DialerImpression.Type.IMS_VIDEO_REQUESTED_FROM_CALL_LOG)
+          .put(
+              Event.REQUEST_DUO_VIDEO_CALL,
+              DialerImpression.Type.LIGHTBRINGER_VIDEO_REQUESTED_FROM_CALL_LOG)
+          .put(
+              Event.REQUEST_DUO_VIDEO_CALL_FOR_NON_CONTACT,
+              DialerImpression.Type.LIGHTBRINGER_NON_CONTACT_VIDEO_REQUESTED_FROM_CALL_LOG)
+          .put(Event.SEND_TEXT_MESSAGE, DialerImpression.Type.CALL_LOG_SEND_MESSAGE)
+          .put(Event.UNBLOCK_NUMBER, DialerImpression.Type.CALL_LOG_UNBLOCK_NUMBER)
+          .build();
+
   private final Context context;
   private final HistoryItemActionModuleInfo moduleInfo;
   private final List<HistoryItemActionModule> modules;
@@ -158,7 +213,14 @@
 
     // If the module info is for a video call, add an appropriate video call module.
     if ((moduleInfo.getFeatures() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO) {
-      modules.add(IntentModule.newCallModule(context, callIntentBuilder.setIsDuoCall(isDuoCall())));
+      boolean isDuoCall = isDuoCall();
+      modules.add(
+          IntentModule.newCallModule(
+              context,
+              callIntentBuilder.setIsDuoCall(isDuoCall),
+              isDuoCall
+                  ? getImpressionsForDuoVideoCall()
+                  : getImpressions(Event.REQUEST_CARRIER_VIDEO_CALL)));
       return this;
     }
 
@@ -167,14 +229,29 @@
     //
     // The carrier video call module takes precedence over the Duo module.
     if (canPlaceCarrierVideoCall()) {
-      modules.add(IntentModule.newCallModule(context, callIntentBuilder));
+      modules.add(
+          IntentModule.newCallModule(
+              context, callIntentBuilder, getImpressions(Event.REQUEST_CARRIER_VIDEO_CALL)));
     } else if (canPlaceDuoCall()) {
-      modules.add(IntentModule.newCallModule(context, callIntentBuilder.setIsDuoCall(true)));
+      modules.add(
+          IntentModule.newCallModule(
+              context, callIntentBuilder.setIsDuoCall(true), getImpressionsForDuoVideoCall()));
     }
     return this;
   }
 
   /**
+   * Returns a list of impressions to be logged when the user taps the module that attempts to
+   * initiate a Duo video call.
+   */
+  private ImmutableList<DialerImpression.Type> getImpressionsForDuoVideoCall() {
+    return isExistingContact()
+        ? getImpressions(Event.REQUEST_DUO_VIDEO_CALL)
+        : getImpressions(
+            Event.REQUEST_DUO_VIDEO_CALL, Event.REQUEST_DUO_VIDEO_CALL_FOR_NON_CONTACT);
+  }
+
+  /**
    * Adds a module for sending text messages.
    *
    * <p>The method is a no-op if
@@ -199,7 +276,8 @@
     }
 
     modules.add(
-        IntentModule.newModuleForSendingTextMessage(context, moduleInfo.getNormalizedNumber()));
+        IntentModule.newModuleForSendingTextMessage(
+            context, moduleInfo.getNormalizedNumber(), getImpressions(Event.SEND_TEXT_MESSAGE)));
     return this;
   }
 
@@ -256,7 +334,8 @@
             context,
             intent,
             R.string.add_to_contacts,
-            R.drawable.quantum_ic_person_add_vd_theme_24));
+            R.drawable.quantum_ic_person_add_vd_theme_24,
+            getImpressions(Event.ADD_TO_CONTACT)));
     return this;
   }
 
@@ -302,11 +381,13 @@
     if (Spam.shouldShowAsSpam(moduleInfo.getIsSpam(), moduleInfo.getCallType())) {
       modules.add(
           BlockReportSpamModules.moduleForMarkingNumberAsNotSpam(
-              context, blockReportSpamDialogInfo));
+              context, blockReportSpamDialogInfo, getImpression(Event.REPORT_NOT_SPAM)));
       modules.add(
           moduleInfo.getIsBlocked()
-              ? BlockReportSpamModules.moduleForUnblockingNumber(context, blockReportSpamDialogInfo)
-              : BlockReportSpamModules.moduleForBlockingNumber(context, blockReportSpamDialogInfo));
+              ? BlockReportSpamModules.moduleForUnblockingNumber(
+                  context, blockReportSpamDialogInfo, getImpression(Event.UNBLOCK_NUMBER))
+              : BlockReportSpamModules.moduleForBlockingNumber(
+                  context, blockReportSpamDialogInfo, getImpression(Event.BLOCK_NUMBER)));
       return this;
     }
 
@@ -314,7 +395,8 @@
     // "Unblock" module.
     if (moduleInfo.getIsBlocked()) {
       modules.add(
-          BlockReportSpamModules.moduleForUnblockingNumber(context, blockReportSpamDialogInfo));
+          BlockReportSpamModules.moduleForUnblockingNumber(
+              context, blockReportSpamDialogInfo, getImpression(Event.UNBLOCK_NUMBER)));
       return this;
     }
 
@@ -322,7 +404,7 @@
     // spam, add the "Block/Report spam" module.
     modules.add(
         BlockReportSpamModules.moduleForBlockingNumberAndOptionallyReportingSpam(
-            context, blockReportSpamDialogInfo));
+            context, blockReportSpamDialogInfo, getImpression(Event.BLOCK_NUMBER_AND_REPORT_SPAM)));
     return this;
   }
 
@@ -437,4 +519,34 @@
             String.format("Unsupported host: %s", moduleInfo.getHost()));
     }
   }
+
+  /** Returns a list of impressions to be logged for the given {@link Event events}. */
+  private ImmutableList<DialerImpression.Type> getImpressions(@Event int... events) {
+    Assert.isNotNull(events);
+
+    ImmutableList.Builder<DialerImpression.Type> impressionListBuilder =
+        new ImmutableList.Builder<>();
+    for (@Event int event : events) {
+      getImpression(event).ifPresent(impressionListBuilder::add);
+    }
+
+    return impressionListBuilder.build();
+  }
+
+  /**
+   * Returns an impression to be logged for the given {@link Event}, or {@link Optional#empty()} if
+   * no impression is available for the event.
+   */
+  private Optional<DialerImpression.Type> getImpression(@Event int event) {
+    switch (moduleInfo.getHost()) {
+      case CALL_LOG:
+        return Optional.of(CALL_LOG_IMPRESSIONS.get(event));
+      case VOICEMAIL:
+        // TODO(a bug): Return proper impressions for voicemail.
+        return Optional.empty();
+      default:
+        throw Assert.createUnsupportedOperationFailException(
+            String.format("Unsupported host: %s", moduleInfo.getHost()));
+    }
+  }
 }
diff --git a/java/com/android/dialer/historyitemactions/IntentModule.java b/java/com/android/dialer/historyitemactions/IntentModule.java
index dc53064..f4fc678 100644
--- a/java/com/android/dialer/historyitemactions/IntentModule.java
+++ b/java/com/android/dialer/historyitemactions/IntentModule.java
@@ -21,9 +21,12 @@
 import android.support.annotation.DrawableRes;
 import android.support.annotation.StringRes;
 import com.android.dialer.callintent.CallIntentBuilder;
+import com.android.dialer.logging.DialerImpression;
+import com.android.dialer.logging.Logger;
 import com.android.dialer.precall.PreCall;
 import com.android.dialer.util.DialerUtils;
 import com.android.dialer.util.IntentUtil;
+import com.google.common.collect.ImmutableList;
 
 /**
  * {@link HistoryItemActionModule} useful for making easy to build modules based on starting an
@@ -35,12 +38,28 @@
   private final Intent intent;
   private final @StringRes int text;
   private final @DrawableRes int image;
+  private final ImmutableList<DialerImpression.Type> impressions;
 
+  /**
+   * @deprecated use {@link IntentModule#IntentModule(Context, Intent, int, int, ImmutableList)}
+   *     instead.
+   */
+  @Deprecated
   public IntentModule(Context context, Intent intent, @StringRes int text, @DrawableRes int image) {
+    this(context, intent, text, image, /* impressions = */ ImmutableList.of());
+  }
+
+  IntentModule(
+      Context context,
+      Intent intent,
+      @StringRes int text,
+      @DrawableRes int image,
+      ImmutableList<DialerImpression.Type> impressions) {
     this.context = context;
     this.intent = intent;
     this.text = text;
     this.image = image;
+    this.impressions = impressions;
   }
 
   @Override
@@ -56,11 +75,21 @@
   @Override
   public boolean onClick() {
     DialerUtils.startActivityWithErrorToast(context, intent);
+    impressions.forEach(Logger.get(context)::logImpression);
     return true;
   }
 
-  /** Creates a module for starting an outgoing call with a {@link CallIntentBuilder}. */
+  /** @deprecated Use {@link #newCallModule(Context, CallIntentBuilder, ImmutableList)} instead. */
+  @Deprecated
   public static IntentModule newCallModule(Context context, CallIntentBuilder callIntentBuilder) {
+    return newCallModule(context, callIntentBuilder, /* impressions = */ ImmutableList.of());
+  }
+
+  /** Creates a module for starting an outgoing call with a {@link CallIntentBuilder}. */
+  static IntentModule newCallModule(
+      Context context,
+      CallIntentBuilder callIntentBuilder,
+      ImmutableList<DialerImpression.Type> impressions) {
     @StringRes int text;
     @DrawableRes int image;
 
@@ -72,14 +101,27 @@
       image = R.drawable.quantum_ic_call_white_24;
     }
 
-    return new IntentModule(context, PreCall.getIntent(context, callIntentBuilder), text, image);
+    return new IntentModule(
+        context, PreCall.getIntent(context, callIntentBuilder), text, image, impressions);
   }
 
+  /**
+   * @deprecated Use {@link #newModuleForSendingTextMessage(Context, String, ImmutableList)}
+   *     instead.
+   */
+  @Deprecated
   public static IntentModule newModuleForSendingTextMessage(Context context, String number) {
+    return newModuleForSendingTextMessage(context, number, /* impressions = */ ImmutableList.of());
+  }
+
+  /** Creates a module for sending a text message to the given number. */
+  static IntentModule newModuleForSendingTextMessage(
+      Context context, String number, ImmutableList<DialerImpression.Type> impressions) {
     return new IntentModule(
         context,
         IntentUtil.getSendSmsIntent(number),
         R.string.send_a_message,
-        R.drawable.quantum_ic_message_vd_theme_24);
+        R.drawable.quantum_ic_message_vd_theme_24,
+        impressions);
   }
 }
diff --git a/java/com/android/incallui/call/DialerCall.java b/java/com/android/incallui/call/DialerCall.java
index fc22762..94724e6 100644
--- a/java/com/android/incallui/call/DialerCall.java
+++ b/java/com/android/incallui/call/DialerCall.java
@@ -1731,7 +1731,27 @@
         && !isConferenceCall()
         && !isVideoCall()
         && !isVoiceMailNumber()
-        && !hasReceivedVideoUpgradeRequest();
+        && !hasReceivedVideoUpgradeRequest()
+        && !isVoipCallNotSupportedBySpeakeasy();
+  }
+
+  private boolean isVoipCallNotSupportedBySpeakeasy() {
+    Bundle extras = getIntentExtras();
+
+    if (extras == null) {
+      return false;
+    }
+
+    // Indicates an VOIP call.
+    String callid = extras.getString("callid");
+
+    if (TextUtils.isEmpty(callid)) {
+      LogUtil.i("DialerCall.isVoipCallNotSupportedBySpeakeasy", "callid was empty");
+      return false;
+    }
+
+    LogUtil.i("DialerCall.isVoipCallNotSupportedBySpeakeasy", "call is not eligible");
+    return true;
   }
 
   /** Indicates the user has selected SpeakEasy */