Don't insert certain numbers into the call log

For regulatory requirements, prevent certain sensitive numbers from
being logged in the call log. The numbers can either be specified in the
carrier config or in the mcc config for the device.

Bug: 111470439
Test: unit, manual
Change-Id: I95040d6927d75b4104b5994e585b9498122448b0
diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java
index 496b6f4..6e71b73 100755
--- a/src/com/android/server/telecom/CallLogManager.java
+++ b/src/com/android/server/telecom/CallLogManager.java
@@ -40,7 +40,14 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.CallerInfo;
 
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.Locale;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * Helper class that provides functionality to write information about calls and their associated
@@ -290,7 +297,8 @@
         }
 
         // Don't log emergency numbers if the device doesn't allow it.
-        final boolean isOkToLogThisCall = !isEmergency || okToLogEmergencyNumber;
+        final boolean isOkToLogThisCall = (!isEmergency || okToLogEmergencyNumber)
+                && !isUnloggableNumber(number, configBundle);
 
         sendAddCallBroadcast(callType, duration);
 
@@ -313,6 +321,21 @@
         }
     }
 
+    private boolean isUnloggableNumber(String callNumber, PersistableBundle carrierConfig) {
+        String normalizedNumber = PhoneNumberUtils.normalizeNumber(callNumber);
+        String[] unloggableNumbersFromCarrierConfig = carrierConfig == null ? null
+                : carrierConfig.getStringArray(
+                        CarrierConfigManager.KEY_UNLOGGABLE_NUMBERS_STRING_ARRAY);
+        String[] unloggableNumbersFromMccConfig = mContext.getResources()
+                .getStringArray(com.android.internal.R.array.unloggable_phone_numbers);
+        return Stream.concat(
+                unloggableNumbersFromCarrierConfig == null ?
+                        Stream.empty() : Arrays.stream(unloggableNumbersFromCarrierConfig),
+                unloggableNumbersFromMccConfig == null ?
+                        Stream.empty() : Arrays.stream(unloggableNumbersFromMccConfig)
+        ).anyMatch(unloggableNumber -> Objects.equals(unloggableNumber, normalizedNumber));
+    }
+
     /**
      * Based on the video state of the call, determines the call features applicable for the call.
      *
diff --git a/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java b/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
index 5840b07..690a38a 100644
--- a/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallLogManagerTest.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.IContentProvider;
 import android.content.pm.UserInfo;
+import android.content.res.Resources;
 import android.location.Country;
 import android.location.CountryDetector;
 import android.location.CountryListener;
@@ -216,6 +217,57 @@
 
     @MediumTest
     @Test
+    public void testDontLogUnloggableNumbers() {
+        // Set up the carrier config source
+        String number1 = "90000";
+        String number2 = "80000";
+        CarrierConfigManager mockCarrierConfigManager =
+                (CarrierConfigManager) mComponentContextFixture.getTestDouble()
+                        .getApplicationContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        PersistableBundle bundle = new PersistableBundle();
+        bundle.putStringArray(CarrierConfigManager.KEY_UNLOGGABLE_NUMBERS_STRING_ARRAY,
+                new String[] {number1});
+        when(mockCarrierConfigManager.getConfig()).thenReturn(bundle);
+
+        Resources mockResources = mContext.getResources();
+        when(mockResources.getStringArray(com.android.internal.R.array.unloggable_phone_numbers))
+                .thenReturn(new String[] {number2});
+
+        Call fakeCall1 = makeFakeCall(
+                DisconnectCause.OTHER, // disconnectCauseCode
+                false, // isConference
+                false, // isIncoming
+                1L, // creationTimeMillis
+                1000L, // ageMillis
+                Uri.parse("tel:" + number1),
+                EMERGENCY_ACCT_HANDLE, // phoneAccountHandle
+                NO_VIDEO_STATE, // callVideoState
+                POST_DIAL_STRING, // postDialDigits
+                VIA_NUMBER_STRING, // viaNumber
+                UserHandle.of(CURRENT_USER_ID)
+        );
+
+        Call fakeCall2 = makeFakeCall(
+                DisconnectCause.OTHER, // disconnectCauseCode
+                false, // isConference
+                false, // isIncoming
+                1L, // creationTimeMillis
+                1000L, // ageMillis
+                Uri.parse("tel:" + number2),
+                EMERGENCY_ACCT_HANDLE, // phoneAccountHandle
+                NO_VIDEO_STATE, // callVideoState
+                POST_DIAL_STRING, // postDialDigits
+                VIA_NUMBER_STRING, // viaNumber
+                UserHandle.of(CURRENT_USER_ID)
+        );
+
+        mCallLogManager.onCallStateChanged(fakeCall1, CallState.ACTIVE, CallState.DISCONNECTED);
+        mCallLogManager.onCallStateChanged(fakeCall2, CallState.ACTIVE, CallState.DISCONNECTED);
+        verifyNoInsertion();
+    }
+
+    @MediumTest
+    @Test
     public void testDontLogCallsFromEmergencyAccount() {
         when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class)))
                 .thenReturn(makeFakePhoneAccount(EMERGENCY_ACCT_HANDLE, 0));