Don't show an outgoing call to a spam number as spam.

Bug: 79770053
Test: SpamTest + Existing tests
PiperOrigin-RevId: 197201496
Change-Id: Iff2eb03d00d3b559d2a008487b19a2d044b2cb5b
diff --git a/java/com/android/dialer/calllogutils/CallLogEntryText.java b/java/com/android/dialer/calllogutils/CallLogEntryText.java
index 54b1e19..acf8ef9 100644
--- a/java/com/android/dialer/calllogutils/CallLogEntryText.java
+++ b/java/com/android/dialer/calllogutils/CallLogEntryText.java
@@ -21,6 +21,7 @@
 import android.text.TextUtils;
 import com.android.dialer.calllog.model.CoalescedRow;
 import com.android.dialer.duo.DuoComponent;
+import com.android.dialer.spam.Spam;
 import com.android.dialer.time.Clock;
 import com.google.common.base.Optional;
 import com.google.common.collect.Collections2;
@@ -80,13 +81,15 @@
    * <p>Rules:
    *
    * <ul>
-   *   <li>For emergency numbers: Date
-   *   <li>For numbers that are not spam or blocked: $Label(, Duo video|Carrier video)?|$Location •
-   *       Date
-   *   <li>For blocked non-spam numbers: Blocked • $Label(, Duo video|Carrier video)?|$Location •
-   *       Date
-   *   <li>For spam but not blocked numbers: Spam • $Label(, Duo video|Carrier video)? • Date
-   *   <li>For blocked spam numbers: Blocked • Spam • $Label(, Duo video|Carrier video)? • Date
+   *   <li>An emergency number: Date
+   *   <li>Number - not blocked, call - not spam:
+   *       <p>$Label(, Duo video|Carrier video)?|$Location • Date
+   *   <li>Number - blocked, call - not spam:
+   *       <p>Blocked • $Label(, Duo video|Carrier video)?|$Location • Date
+   *   <li>Number - not blocked, call - spam:
+   *       <p>Spam • $Label(, Duo video|Carrier video)? • Date
+   *   <li>Number - blocked, call - spam:
+   *       <p>Blocked • Spam • $Label(, Duo video|Carrier video)? • Date
    * </ul>
    *
    * <p>Examples:
@@ -119,7 +122,7 @@
     if (row.getNumberAttributes().getIsBlocked()) {
       components.add(context.getText(R.string.new_call_log_secondary_blocked));
     }
-    if (row.getNumberAttributes().getIsSpam()) {
+    if (Spam.shouldShowAsSpam(row.getNumberAttributes().getIsSpam(), row.getCallType())) {
       components.add(context.getText(R.string.new_call_log_secondary_spam));
     }
 
@@ -141,15 +144,15 @@
   public static CharSequence buildSecondaryTextForBottomSheet(Context context, CoalescedRow row) {
     /*
      * Rules:
-     *   For emergency numbers:
+     *   For an emergency number:
      *     Number
-     *   For numbers that are not spam or blocked:
+     *   Number - not blocked, call - not spam:
      *     $Label(, Duo video|Carrier video)?|$Location [• NumberIfNoName]?
-     *   For blocked non-spam numbers:
+     *   Number - blocked, call - not spam:
      *     Blocked • $Label(, Duo video|Carrier video)?|$Location [• NumberIfNoName]?
-     *   For spam but not blocked numbers:
+     *   Number - not blocked, call - spam:
      *     Spam • $Label(, Duo video|Carrier video)? [• NumberIfNoName]?
-     *   For blocked spam numbers:
+     *   Number - blocked, call - spam:
      *     Blocked • Spam • $Label(, Duo video|Carrier video)? [• NumberIfNoName]?
      *
      * The number is shown at the end if there is no name for the entry. (It is shown in primary
@@ -178,7 +181,7 @@
     if (row.getNumberAttributes().getIsBlocked()) {
       components.add(context.getText(R.string.new_call_log_secondary_blocked));
     }
-    if (row.getNumberAttributes().getIsSpam()) {
+    if (Spam.shouldShowAsSpam(row.getNumberAttributes().getIsSpam(), row.getCallType())) {
       components.add(context.getText(R.string.new_call_log_secondary_spam));
     }
 
@@ -234,8 +237,9 @@
 
     // Show the location if
     // (1) there is no number type label, and
-    // (2) the number is not spam.
-    if (TextUtils.isEmpty(numberTypeLabel) && !row.getNumberAttributes().getIsSpam()) {
+    // (2) the call should not be shown as spam.
+    if (TextUtils.isEmpty(numberTypeLabel)
+        && !Spam.shouldShowAsSpam(row.getNumberAttributes().getIsSpam(), row.getCallType())) {
       // If number attributes contain a location (obtained from a PhoneLookup), use it instead
       // of the one from the annotated call log.
       String location =
diff --git a/java/com/android/dialer/calllogutils/PhotoInfoBuilder.java b/java/com/android/dialer/calllogutils/PhotoInfoBuilder.java
index 8d193bf..0677c91 100644
--- a/java/com/android/dialer/calllogutils/PhotoInfoBuilder.java
+++ b/java/com/android/dialer/calllogutils/PhotoInfoBuilder.java
@@ -21,6 +21,7 @@
 import com.android.dialer.NumberAttributes;
 import com.android.dialer.calllog.model.CoalescedRow;
 import com.android.dialer.glidephotomanager.PhotoInfo;
+import com.android.dialer.spam.Spam;
 import com.android.dialer.voicemail.model.VoicemailEntry;
 
 /** Builds {@link PhotoInfo} from other data types. */
@@ -31,6 +32,9 @@
     return fromNumberAttributes(coalescedRow.getNumberAttributes())
         .setFormattedNumber(coalescedRow.getFormattedNumber())
         .setIsVoicemail(coalescedRow.getIsVoicemailCall())
+        .setIsSpam(
+            Spam.shouldShowAsSpam(
+                coalescedRow.getNumberAttributes().getIsSpam(), coalescedRow.getCallType()))
         .setIsVideo((coalescedRow.getFeatures() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO)
         .setIsRtt(
             BuildCompat.isAtLeastP()
@@ -40,7 +44,10 @@
   /** Returns a {@link PhotoInfo.Builder} with info from {@link VoicemailEntry}. */
   public static PhotoInfo.Builder fromVoicemailEntry(VoicemailEntry voicemailEntry) {
     return fromNumberAttributes(voicemailEntry.getNumberAttributes())
-        .setFormattedNumber(voicemailEntry.getFormattedNumber());
+        .setFormattedNumber(voicemailEntry.getFormattedNumber())
+        .setIsSpam(
+            Spam.shouldShowAsSpam(
+                voicemailEntry.getNumberAttributes().getIsSpam(), voicemailEntry.getCallType()));
   }
 
   /** Returns a {@link PhotoInfo.Builder} with info from {@link NumberAttributes}. */
@@ -51,7 +58,6 @@
         .setPhotoId(numberAttributes.getPhotoId())
         .setLookupUri(numberAttributes.getLookupUri())
         .setIsBusiness(numberAttributes.getIsBusiness())
-        .setIsBlocked(numberAttributes.getIsBlocked())
-        .setIsSpam(numberAttributes.getIsSpam());
+        .setIsBlocked(numberAttributes.getIsBlocked());
   }
 }
diff --git a/java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java b/java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java
index e1c6c96..a09f6e1 100644
--- a/java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java
+++ b/java/com/android/dialer/historyitemactions/HistoryItemActionModulesBuilder.java
@@ -30,6 +30,7 @@
 import com.android.dialer.duo.Duo;
 import com.android.dialer.duo.DuoComponent;
 import com.android.dialer.logging.ReportingLocation;
+import com.android.dialer.spam.Spam;
 import com.android.dialer.util.CallUtil;
 import com.android.dialer.util.UriUtils;
 import java.util.ArrayList;
@@ -120,8 +121,8 @@
    * <ul>
    *   <li>the call is one made to/received from an emergency number,
    *   <li>the call is one made to a voicemail box,
-   *   <li>the number is blocked, or
-   *   <li>the number is marked as spam.
+   *   <li>the call should be shown as spam, or
+   *   <li>the number is blocked.
    * </ul>
    *
    * <p>If the provided module info is for a Duo video call and Duo is available, add a Duo video
@@ -141,8 +142,8 @@
   public HistoryItemActionModulesBuilder addModuleForVideoCall() {
     if (moduleInfo.getIsEmergencyNumber()
         || moduleInfo.getIsVoicemailCall()
-        || moduleInfo.getIsBlocked()
-        || moduleInfo.getIsSpam()) {
+        || Spam.shouldShowAsSpam(moduleInfo.getIsSpam(), moduleInfo.getCallType())
+        || moduleInfo.getIsBlocked()) {
       return this;
     }
 
@@ -221,8 +222,8 @@
    * <ul>
    *   <li>the call is one made to/received from an emergency number,
    *   <li>the call is one made to a voicemail box,
+   *   <li>the call should be shown as spam,
    *   <li>the number is blocked,
-   *   <li>the number is marked as spam,
    *   <li>the number is empty, or
    *   <li>the number belongs to an existing contact.
    * </ul>
@@ -230,8 +231,8 @@
   public HistoryItemActionModulesBuilder addModuleForAddingToContacts() {
     if (moduleInfo.getIsEmergencyNumber()
         || moduleInfo.getIsVoicemailCall()
+        || Spam.shouldShowAsSpam(moduleInfo.getIsSpam(), moduleInfo.getCallType())
         || moduleInfo.getIsBlocked()
-        || moduleInfo.getIsSpam()
         || isExistingContact()
         || TextUtils.isEmpty(moduleInfo.getNormalizedNumber())) {
       return this;
@@ -264,16 +265,17 @@
    *   <li>the call is one made to a voicemail box.
    * </ul>
    *
-   * <p>If a number is marked as spam, add two modules:
+   * <p>If the call should be shown as spam, add two modules:
    *
    * <ul>
    *   <li>"Not spam" and "Block", or
    *   <li>"Not spam" and "Unblock".
    * </ul>
    *
-   * <p>If a number is blocked but not marked as spam, add the "Unblock" module.
+   * <p>If the number is blocked but the call should not be shown as spam, add the "Unblock" module.
    *
-   * <p>If a number is not blocked or marked as spam, add the "Block/Report spam" module.
+   * <p>If the number is not blocked and the call should not be shown as spam, add the "Block/Report
+   * spam" module.
    */
   public HistoryItemActionModulesBuilder addModuleForBlockedOrSpamNumber() {
     if (moduleInfo.getIsEmergencyNumber() || moduleInfo.getIsVoicemailCall()) {
@@ -289,10 +291,10 @@
             .setContactSource(moduleInfo.getContactSource())
             .build();
 
-    // For a spam number, add two modules:
+    // For a call that should be shown as spam, add two modules:
     // (1) "Not spam" and "Block", or
     // (2) "Not spam" and "Unblock".
-    if (moduleInfo.getIsSpam()) {
+    if (Spam.shouldShowAsSpam(moduleInfo.getIsSpam(), moduleInfo.getCallType())) {
       modules.add(
           BlockReportSpamModules.moduleForMarkingNumberAsNotSpam(
               context, blockReportSpamDialogInfo));
@@ -303,14 +305,16 @@
       return this;
     }
 
-    // For a blocked non-spam number, add the "Unblock" module.
+    // For a blocked number associated with a call that should not be shown as spam, add the
+    // "Unblock" module.
     if (moduleInfo.getIsBlocked()) {
       modules.add(
           BlockReportSpamModules.moduleForUnblockingNumber(context, blockReportSpamDialogInfo));
       return this;
     }
 
-    // For a number that is neither a spam number nor blocked, add the "Block/Report spam" module.
+    // For a number that is not blocked and is associated with a call that should not be shown as
+    // spam, add the "Block/Report spam" module.
     modules.add(
         BlockReportSpamModules.moduleForBlockingNumberAndOptionallyReportingSpam(
             context, blockReportSpamDialogInfo));
diff --git a/java/com/android/dialer/spam/Spam.java b/java/com/android/dialer/spam/Spam.java
index 0229782..028bda4 100644
--- a/java/com/android/dialer/spam/Spam.java
+++ b/java/com/android/dialer/spam/Spam.java
@@ -18,6 +18,7 @@
 
 import android.preference.Preference;
 import android.preference.Preference.OnPreferenceChangeListener;
+import android.provider.CallLog.Calls;
 import android.support.annotation.Nullable;
 import com.android.dialer.DialerPhoneNumber;
 import com.android.dialer.logging.ContactLookupResult;
@@ -166,4 +167,25 @@
       int callType,
       ReportingLocation.Type from,
       ContactSource.Type contactSourceType);
+
+  /**
+   * Given a number's spam status and a call type, determine if the call should be shown as spam.
+   *
+   * <p>We show a call as spam if
+   *
+   * <ul>
+   *   <li>the number is marked as spam, and
+   *   <li>the call is not an outgoing call.
+   * </ul>
+   *
+   * <p>This is because spammers can hide behind a legit number (e.g., a customer service number).
+   * We don't want to show a spam icon when users call it.
+   *
+   * @param isNumberSpam Whether the number is spam.
+   * @param callType One of the types in {@link android.provider.CallLog.Calls#TYPE}.
+   * @return true if the number is spam *and* the call is not an outgoing call.
+   */
+  static boolean shouldShowAsSpam(boolean isNumberSpam, int callType) {
+    return isNumberSpam && (callType != Calls.OUTGOING_TYPE);
+  }
 }