Remove hidden Telephony API usages from Telecom

Inline utility methods from BlockChecker and
AsyncEmergencyContactNotifier, and use the new API from
TelephonyRegistryManager in PhoneStateBroadcaster.

Also fix a flaky test

Bug: 141576016
Fixes: 144264937
Test: unit, cts
Change-Id: I6108d0e1c97f15b096c8b07f529edf5c3a7ee058
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 63fe1f4..9e8cf22 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -46,6 +46,7 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.BlockedNumberContract;
 import android.provider.BlockedNumberContract.SystemContract;
 import android.provider.CallLog.Calls;
 import android.provider.Settings;
@@ -111,6 +112,7 @@
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
@@ -1993,7 +1995,9 @@
         }
 
         if (call.isEmergencyCall()) {
-            new AsyncEmergencyContactNotifier(mContext).execute();
+            Executors.defaultThreadFactory().newThread(() ->
+                    BlockedNumberContract.SystemContract.notifyEmergencyContact(mContext))
+                    .start();
         }
 
         final boolean requireCallCapableAccountByHandle = mContext.getResources().getBoolean(
@@ -4800,6 +4804,10 @@
         }
     }
 
+    public Context getContext() {
+        return mContext;
+    }
+
     /**
      * Determines if there is an ongoing emergency call. This can be either an outgoing emergency
      * call, or a number which has been identified by the number as an emergency call.
diff --git a/src/com/android/server/telecom/PhoneStateBroadcaster.java b/src/com/android/server/telecom/PhoneStateBroadcaster.java
index 533c81c..f2531ed 100644
--- a/src/com/android/server/telecom/PhoneStateBroadcaster.java
+++ b/src/com/android/server/telecom/PhoneStateBroadcaster.java
@@ -16,12 +16,9 @@
 
 package com.android.server.telecom;
 
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.telecom.Log;
 import android.telephony.TelephonyManager;
-
-import com.android.internal.telephony.ITelephonyRegistry;
+import android.telephony.TelephonyRegistryManager;
 
 /**
  * Send a {@link TelephonyManager#ACTION_PHONE_STATE_CHANGED} broadcast when the call state
@@ -30,13 +27,12 @@
 final class PhoneStateBroadcaster extends CallsManagerListenerBase {
 
     private final CallsManager mCallsManager;
-    private final ITelephonyRegistry mRegistry;
+    private final TelephonyRegistryManager mRegistry;
     private int mCurrentState = TelephonyManager.CALL_STATE_IDLE;
 
     public PhoneStateBroadcaster(CallsManager callsManager) {
         mCallsManager = callsManager;
-        mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
-                "telephony.registry"));
+        mRegistry = callsManager.getContext().getSystemService(TelephonyRegistryManager.class);
         if (mRegistry == null) {
             Log.w(this, "TelephonyRegistry is null");
         }
@@ -112,13 +108,9 @@
             callHandle = call.getHandle().getSchemeSpecificPart();
         }
 
-        try {
-            if (mRegistry != null) {
-                mRegistry.notifyCallStateForAllSubs(phoneState, callHandle);
-                Log.i(this, "Broadcasted state change: %s", mCurrentState);
-            }
-        } catch (RemoteException e) {
-            Log.w(this, "RemoteException when notifying TelephonyRegistry of call state change.");
+        if (mRegistry != null) {
+            mRegistry.notifyCallStateChangedForAllSubscriptions(phoneState, callHandle);
+            Log.i(this, "Broadcasted state change: %s", mCurrentState);
         }
     }
 }
diff --git a/src/com/android/server/telecom/callfiltering/BlockCheckerAdapter.java b/src/com/android/server/telecom/callfiltering/BlockCheckerAdapter.java
index 4a5ac60..1a641f0 100644
--- a/src/com/android/server/telecom/callfiltering/BlockCheckerAdapter.java
+++ b/src/com/android/server/telecom/callfiltering/BlockCheckerAdapter.java
@@ -18,27 +18,51 @@
 
 import android.content.Context;
 import android.os.Bundle;
+import android.provider.BlockedNumberContract;
+import android.telecom.Log;
 
 import com.android.internal.telephony.BlockChecker;
 
 public class BlockCheckerAdapter {
+    private static final String TAG = BlockCheckerAdapter.class.getSimpleName();
+
     public BlockCheckerAdapter() { }
 
     /**
-     * Check whether the number is blocked.
+     * Returns the call blocking status for the {@code phoneNumber}.
+     * <p>
+     * This method catches all underlying exceptions to ensure that this method never throws any
+     * exception.
      *
      * @param context the context of the caller.
-     * @param number the number to check.
+     * @param phoneNumber the number to check.
      * @param extras the extra attribute of the number.
      * @return result code indicating if the number should be blocked, and if so why.
-     *         Valid values are: {@link android.provider.BlockedNumberContract#STATUS_NOT_BLOCKED},
-     *         {@link android.provider.BlockedNumberContract#STATUS_BLOCKED_IN_LIST},
-     *         {@link android.provider.BlockedNumberContract#STATUS_BLOCKED_NOT_IN_CONTACTS},
-     *         {@link android.provider.BlockedNumberContract#STATUS_BLOCKED_PAYPHONE},
-     *         {@link android.provider.BlockedNumberContract#STATUS_BLOCKED_RESTRICTED},
-     *         {@link android.provider.BlockedNumberContract#STATUS_BLOCKED_UNKNOWN_NUMBER}.
+     *         Valid values are: {@link BlockedNumberContract#STATUS_NOT_BLOCKED},
+     *         {@link BlockedNumberContract#STATUS_BLOCKED_IN_LIST},
+     *         {@link BlockedNumberContract#STATUS_BLOCKED_NOT_IN_CONTACTS},
+     *         {@link BlockedNumberContract#STATUS_BLOCKED_PAYPHONE},
+     *         {@link BlockedNumberContract#STATUS_BLOCKED_RESTRICTED},
+     *         {@link BlockedNumberContract#STATUS_BLOCKED_UNKNOWN_NUMBER}.
      */
-    public int getBlockStatus(Context context, String number, Bundle extras) {
-        return BlockChecker.getBlockStatus(context, number, extras);
+    public int getBlockStatus(Context context, String phoneNumber, Bundle extras) {
+        int blockStatus = BlockedNumberContract.STATUS_NOT_BLOCKED;
+        long startTimeNano = System.nanoTime();
+
+        try {
+            blockStatus = BlockedNumberContract.SystemContract.shouldSystemBlockNumber(
+                    context, phoneNumber, extras);
+            if (blockStatus != BlockedNumberContract.STATUS_NOT_BLOCKED) {
+                Log.d(TAG, phoneNumber + " is blocked.");
+            }
+        } catch (Exception e) {
+            Log.e(TAG, e, "Exception checking for blocked number");
+        }
+
+        int durationMillis = (int) ((System.nanoTime() - startTimeNano) / 1000000);
+        if (durationMillis > 500 || Log.isLoggable(android.util.Log.DEBUG)) {
+            Log.d(TAG, "Blocked number lookup took: " + durationMillis + " ms.");
+        }
+        return blockStatus;
     }
 }
diff --git a/tests/src/com/android/server/telecom/tests/BasicCallTests.java b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
index 5c7b357..322a3c2 100644
--- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
@@ -377,10 +377,13 @@
         waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(),
                 TEST_TIMEOUT);
         assertEquals(1, mCallerInfoAsyncQueryFactoryFixture.mRequests.size());
+
+        CallerInfo sendToVoicemailCallerInfo = new CallerInfo();
+        sendToVoicemailCallerInfo.shouldSendToVoicemail = true;
+        sendToVoicemailCallerInfo.contactExists = true;
+        mCallerInfoAsyncQueryFactoryFixture.setResponse(sendToVoicemailCallerInfo);
         for (CallerInfoAsyncQueryFactoryFixture.Request request :
                 mCallerInfoAsyncQueryFactoryFixture.mRequests) {
-            CallerInfo sendToVoicemailCallerInfo = new CallerInfo();
-            sendToVoicemailCallerInfo.shouldSendToVoicemail = true;
             request.replyWithCallerInfo(sendToVoicemailCallerInfo);
         }
 
diff --git a/tests/src/com/android/server/telecom/tests/CallerInfoAsyncQueryFactoryFixture.java b/tests/src/com/android/server/telecom/tests/CallerInfoAsyncQueryFactoryFixture.java
index c469dbc..68db09c 100644
--- a/tests/src/com/android/server/telecom/tests/CallerInfoAsyncQueryFactoryFixture.java
+++ b/tests/src/com/android/server/telecom/tests/CallerInfoAsyncQueryFactoryFixture.java
@@ -27,7 +27,9 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Controls a test {@link CallerInfoAsyncQueryFactory} to abstract away the asynchronous retrieval
@@ -58,16 +60,24 @@
             r.mCookie = cookie;
             r.mListener = listener;
             mRequests.add(r);
+            if (mStoredResponse != null) {
+                listener.onQueryComplete(token, cookie, mStoredResponse);
+            }
             return Mockito.mock(CallerInfoAsyncQuery.class);
         }
     };
 
     final List<Request> mRequests = Collections.synchronizedList(new ArrayList<Request>());
+    private CallerInfo mStoredResponse;
 
     public CallerInfoAsyncQueryFactoryFixture() throws Exception {
         Log.i(this, "Creating ...");
     }
 
+    public void setResponse(CallerInfo callerInfo) {
+        mStoredResponse = callerInfo;
+    }
+
     @Override
     public CallerInfoAsyncQueryFactory getTestDouble() {
         return mCallerInfoAsyncQueryFactory;
diff --git a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
index dcd0607..91ee977 100644
--- a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
@@ -63,6 +63,7 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.TelephonyRegistryManager;
 import android.test.mock.MockContext;
 
 import java.io.File;
@@ -195,6 +196,8 @@
                     return mCountryDetector;
                 case Context.ROLE_SERVICE:
                     return mRoleManager;
+                case Context.TELEPHONY_REGISTRY_SERVICE:
+                    return mTelephonyRegistryManager;
                 default:
                     return null;
             }
@@ -214,6 +217,8 @@
                 return Context.CARRIER_CONFIG_SERVICE;
             } else if (svcClass == SubscriptionManager.class) {
                 return Context.TELEPHONY_SUBSCRIPTION_SERVICE;
+            } else if (svcClass == TelephonyRegistryManager.class) {
+                return Context.TELEPHONY_REGISTRY_SERVICE;
             }
             throw new UnsupportedOperationException();
         }
@@ -463,6 +468,8 @@
     private final Configuration mResourceConfiguration = new Configuration();
     private final ApplicationInfo mTestApplicationInfo = new ApplicationInfo();
     private final RoleManager mRoleManager = mock(RoleManager.class);
+    private final TelephonyRegistryManager mTelephonyRegistryManager =
+            mock(TelephonyRegistryManager.class);
 
     private TelecomManager mTelecomManager = mock(TelecomManager.class);
 
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index cfc530d..a3b102f 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -62,6 +62,8 @@
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
+import android.telephony.TelephonyManager;
+import android.telephony.TelephonyRegistryManager;
 import android.text.TextUtils;
 
 import com.android.internal.telecom.IInCallAdapter;
@@ -1022,6 +1024,16 @@
         if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
             assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
             assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+
+            if ((mInCallServiceFixtureX.getCall(ids.mCallId).getProperties() &
+                    Call.Details.PROPERTY_IS_EXTERNAL_CALL) == 0) {
+                // Test the PhoneStateBroadcaster functionality if the call is not external.
+                verify(mContext.getSystemService(TelephonyRegistryManager.class),
+                        timeout(TEST_TIMEOUT).atLeastOnce())
+                        .notifyCallStateChangedForAllSubscriptions(
+                                eq(TelephonyManager.CALL_STATE_OFFHOOK),
+                                nullable(String.class));
+            }
         }
         return ids;
     }
@@ -1070,6 +1082,16 @@
         if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) {
             assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
             assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+
+            if ((mInCallServiceFixtureX.getCall(ids.mCallId).getProperties() &
+                    Call.Details.PROPERTY_IS_EXTERNAL_CALL) == 0) {
+                // Test the PhoneStateBroadcaster functionality if the call is not external.
+                verify(mContext.getSystemService(TelephonyRegistryManager.class),
+                        timeout(TEST_TIMEOUT).atLeastOnce())
+                        .notifyCallStateChangedForAllSubscriptions(
+                                eq(TelephonyManager.CALL_STATE_OFFHOOK),
+                                nullable(String.class));
+            }
         }
         return ids;
     }