Replace callers of SmsApplication with user-aware
methods.

Bug: 250617029
Test: Sending and receiving SMS/MMS,
      atest com.android.internal.telephony.tests.SmsApplicationTest
Change-Id: Idb6671d35bed6a35804b5553f75d461b54273612
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 693f3a0..1bd5031 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -788,7 +788,7 @@
 
     private void updateDefaultSmsApp(@NonNull UserData userData) {
         ComponentName component = SmsApplication.getDefaultSmsApplicationAsUser(
-                mContext, /* updateIfNeeded= */ false, userData.getUserId());
+                mContext, /* updateIfNeeded= */ false, UserHandle.of(userData.getUserId()));
         String defaultSmsApp = component != null ? component.getPackageName() : null;
         userData.setDefaultSmsApp(defaultSmsApp);
     }
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index f848c40..a9cdf7e 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -210,6 +210,15 @@
     }
 
     /**
+     * Returns the userHandle of the current process, if called from a system app,
+     * otherwise it returns the caller's userHandle
+     * @return userHandle of the caller.
+     */
+    private static UserHandle getIncomingUserHandle() {
+        return UserHandle.of(getIncomingUserId());
+    }
+
+    /**
      * Returns the list of available SMS apps defined as apps that are registered for both the
      * SMS_RECEIVED_ACTION (SMS) and WAP_PUSH_RECEIVED_ACTION (MMS) broadcasts (and their broadcast
      * receivers are enabled)
@@ -951,24 +960,28 @@
      */
     @UnsupportedAppUsage
     public static ComponentName getDefaultSmsApplication(Context context, boolean updateIfNeeded) {
-        return getDefaultSmsApplicationAsUser(context, updateIfNeeded, getIncomingUserId());
+        return getDefaultSmsApplicationAsUser(context, updateIfNeeded, getIncomingUserHandle());
     }
 
     /**
      * Gets the default SMS application on a given user
      * @param context context from the calling app
      * @param updateIfNeeded update the default app if there is no valid default app configured.
-     * @param userId target user ID.
+     * @param userHandle target user handle
+     * if {@code null} is passed in then calling package uid is used to find out target user handle.
      * @return component name of the app and class to deliver SMS messages to
      */
-    @VisibleForTesting
     public static ComponentName getDefaultSmsApplicationAsUser(Context context,
-            boolean updateIfNeeded, int userId) {
+            boolean updateIfNeeded, @Nullable UserHandle userHandle) {
+        if (userHandle == null) {
+            userHandle = getIncomingUserHandle();
+        }
+
         final long token = Binder.clearCallingIdentity();
         try {
             ComponentName component = null;
             SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
-                    userId);
+                    userHandle.getIdentifier());
             if (smsApplicationData != null) {
                 component = new ComponentName(smsApplicationData.mPackageName,
                         smsApplicationData.mSmsReceiverClass);
@@ -987,23 +1000,28 @@
      */
     @UnsupportedAppUsage
     public static ComponentName getDefaultMmsApplication(Context context, boolean updateIfNeeded) {
-        return getDefaultMmsApplicationAsUser(context, updateIfNeeded, getIncomingUserId());
+        return getDefaultMmsApplicationAsUser(context, updateIfNeeded, getIncomingUserHandle());
     }
 
     /**
      * Gets the default MMS application on a given user
      * @param context context from the calling app
      * @param updateIfNeeded update the default app if there is no valid default app configured.
-     * @param userId target user ID.
+     * @param userHandle target user handle
+     * if {@code null} is passed in then calling package uid is used to find out target user handle.
      * @return component name of the app and class to deliver MMS messages to.
      */
     public static ComponentName getDefaultMmsApplicationAsUser(Context context,
-            boolean updateIfNeeded, int userId) {
+            boolean updateIfNeeded, @Nullable UserHandle userHandle) {
+        if (userHandle == null) {
+            userHandle = getIncomingUserHandle();
+        }
+
         final long token = Binder.clearCallingIdentity();
         try {
             ComponentName component = null;
             SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
-                    userId);
+                    userHandle.getIdentifier());
             if (smsApplicationData != null) {
                 component = new ComponentName(smsApplicationData.mPackageName,
                         smsApplicationData.mMmsReceiverClass);
@@ -1024,23 +1042,28 @@
     public static ComponentName getDefaultRespondViaMessageApplication(Context context,
             boolean updateIfNeeded) {
         return getDefaultRespondViaMessageApplicationAsUser(context, updateIfNeeded,
-                getIncomingUserId());
+                getIncomingUserHandle());
     }
 
     /**
      * Gets the default Respond Via Message application on a given user
      * @param context context from the calling app
      * @param updateIfNeeded update the default app if there is no valid default app configured
-     * @param userId target user ID.
+     * @param userHandle target user handle
+     * if {@code null} is passed in then calling package uid is used to find out target user handle.
      * @return component name of the app and class to direct Respond Via Message intent to
      */
     public static ComponentName getDefaultRespondViaMessageApplicationAsUser(Context context,
-            boolean updateIfNeeded, int userId) {
+            boolean updateIfNeeded, @Nullable UserHandle userHandle) {
+        if (userHandle == null) {
+            userHandle = getIncomingUserHandle();
+        }
+
         final long token = Binder.clearCallingIdentity();
         try {
             ComponentName component = null;
             SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
-                    userId);
+                    userHandle.getIdentifier());
             if (smsApplicationData != null) {
                 component = new ComponentName(smsApplicationData.mPackageName,
                         smsApplicationData.mRespondViaMessageClass);
@@ -1062,6 +1085,7 @@
     public static ComponentName getDefaultSendToApplication(Context context,
             boolean updateIfNeeded) {
         int userId = getIncomingUserId();
+
         final long token = Binder.clearCallingIdentity();
         try {
             ComponentName component = null;
@@ -1087,7 +1111,7 @@
     public static ComponentName getDefaultExternalTelephonyProviderChangedApplication(
             Context context, boolean updateIfNeeded) {
         return getDefaultExternalTelephonyProviderChangedApplicationAsUser(context, updateIfNeeded,
-                getIncomingUserId());
+                getIncomingUserHandle());
     }
 
     /**
@@ -1095,16 +1119,21 @@
      * MmsProvider on a given user.
      * @param context context from the calling app
      * @param updateIfNeeded update the default app if there is no valid default app configured
-     * @param userId target user ID.
+     * @param userHandle target user handle
+     * if {@code null} is passed in then calling package uid is used to find out target user handle.
      * @return component name of the app and class to deliver change intents to.
      */
     public static ComponentName getDefaultExternalTelephonyProviderChangedApplicationAsUser(
-            Context context, boolean updateIfNeeded, int userId) {
+            Context context, boolean updateIfNeeded, @Nullable UserHandle userHandle) {
+        if (userHandle == null) {
+            userHandle = getIncomingUserHandle();
+        }
+
         final long token = Binder.clearCallingIdentity();
         try {
             ComponentName component = null;
             SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
-                    userId);
+                    userHandle.getIdentifier());
             if (smsApplicationData != null
                     && smsApplicationData.mProviderChangedReceiverClass != null) {
                 component = new ComponentName(smsApplicationData.mPackageName,
@@ -1124,23 +1153,28 @@
      */
     public static ComponentName getDefaultSimFullApplication(
             Context context, boolean updateIfNeeded) {
-        return getDefaultSimFullApplicationAsUser(context, updateIfNeeded, getIncomingUserId());
+        return getDefaultSimFullApplicationAsUser(context, updateIfNeeded, getIncomingUserHandle());
     }
 
     /**
      * Gets the default application that handles sim full event on a given user.
      * @param context context from the calling app
      * @param updateIfNeeded update the default app if there is no valid default app configured
-     * @param userId target user ID.
+     * @param userHandle target user handle
+     * if {@code null} is passed in then calling package uid is used to find out target user handle.
      * @return component name of the app and class to deliver change intents to
      */
     public static ComponentName getDefaultSimFullApplicationAsUser(Context context,
-            boolean updateIfNeeded, int userId) {
+            boolean updateIfNeeded, @Nullable UserHandle userHandle) {
+        if (userHandle == null) {
+            userHandle = getIncomingUserHandle();
+        }
+
         final long token = Binder.clearCallingIdentity();
         try {
             ComponentName component = null;
             SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
-                    userId);
+                    userHandle.getIdentifier());
             if (smsApplicationData != null
                     && smsApplicationData.mSimFullReceiverClass != null) {
                 component = new ComponentName(smsApplicationData.mPackageName,
@@ -1153,19 +1187,35 @@
     }
 
     /**
-     * Returns whether need to wrgetIncomingUserIdite the SMS message to SMS database for this
-     * package.
+     * Returns whether it is required to write the SMS message to SMS database for this package.
+     *
+     * @param packageName the name of the package to be checked
+     * @param context context from the calling app
+     * @return true if it is required to write SMS message to SMS database for this package.
+     *
      * <p>
      * Caller must pass in the correct user context if calling from a singleton service.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public static boolean shouldWriteMessageForPackage(String packageName, Context context) {
-        return !shouldWriteMessageForPackageAsUser(packageName, context, getIncomingUserId());
+        return !shouldWriteMessageForPackageAsUser(packageName, context, getIncomingUserHandle());
     }
 
+    /**
+     * Returns whether it is required to write the SMS message to SMS database for this package.
+     *
+     * @param packageName the name of the package to be checked
+     * @param context context from the calling app
+     * @param userHandle target user handle
+     * if {@code null} is passed in then calling package uid is used to find out target user handle.
+     * @return true if it is required to write SMS message to SMS database for this package.
+     *
+     * <p>
+     * Caller must pass in the correct user context if calling from a singleton service.
+     */
     public static boolean shouldWriteMessageForPackageAsUser(String packageName, Context context,
-            int userId) {
-        return !isDefaultSmsApplicationAsUser(context, packageName, userId);
+            @Nullable UserHandle userHandle) {
+        return !isDefaultSmsApplicationAsUser(context, packageName, userHandle);
     }
 
     /**
@@ -1177,7 +1227,7 @@
      */
     @UnsupportedAppUsage
     public static boolean isDefaultSmsApplication(Context context, String packageName) {
-        return isDefaultSmsApplicationAsUser(context, packageName, getIncomingUserId());
+        return isDefaultSmsApplicationAsUser(context, packageName, getIncomingUserHandle());
     }
 
     /**
@@ -1185,16 +1235,22 @@
      *
      * @param context context from the calling app
      * @param packageName the name of the package to be checked
-     * @param userId target user ID.
+     * @param userHandle target user handle
+     * if {@code null} is passed in then calling package uid is used to find out target user handle.
      * @return true if the package is default sms app or bluetooth
      */
     public static boolean isDefaultSmsApplicationAsUser(Context context, String packageName,
-            int userId) {
+            @Nullable UserHandle userHandle) {
         if (packageName == null) {
             return false;
         }
+
+        if (userHandle == null) {
+            userHandle = getIncomingUserHandle();
+        }
+
         ComponentName component = getDefaultSmsApplicationAsUser(context, false,
-                userId);
+                userHandle);
         if (component == null) {
             return false;
         }
@@ -1222,7 +1278,7 @@
      */
     @UnsupportedAppUsage
     public static boolean isDefaultMmsApplication(Context context, String packageName) {
-        return isDefaultMmsApplicationAsUser(context, packageName, getIncomingUserId());
+        return isDefaultMmsApplicationAsUser(context, packageName, getIncomingUserHandle());
     }
 
     /**
@@ -1230,17 +1286,22 @@
      *
      * @param context context from the calling app
      * @param packageName the name of the package to be checked
-     * @param userId target user ID.
+     * @param userHandle target user handle
+     * if {@code null} is passed in then calling package uid is used to find out target user handle.
      * @return true if the package is default mms app or bluetooth
      */
     public static boolean isDefaultMmsApplicationAsUser(Context context, String packageName,
-            int userId) {
+            @Nullable UserHandle userHandle) {
         if (packageName == null) {
             return false;
         }
 
+        if (userHandle == null) {
+            userHandle = getIncomingUserHandle();
+        }
+
         ComponentName component = getDefaultMmsApplicationAsUser(context, false,
-                userId);
+                userHandle);
         if (component == null) {
             return false;
         }
diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
index 76d2b7d..3dc7111 100644
--- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
+++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
@@ -27,6 +27,8 @@
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 
 import java.io.PrintWriter;
@@ -212,4 +214,30 @@
                 return "UNKNOWN(" + mobileDataPolicy + ")";
         }
     }
-}
+
+    /**
+     * Utility method to get user handle associated with this subscription.
+     *
+     * This method should be used internally as it returns null instead of throwing
+     * IllegalArgumentException or IllegalStateException.
+     *
+     * @param context Context object
+     * @param subId the subId of the subscription.
+     * @return userHandle associated with this subscription
+     * or {@code null} if:
+     * 1. subscription is not associated with any user
+     * 2. subId is invalid.
+     * 3. subscription service is not available.
+     *
+     * @throws SecurityException if the caller doesn't have permissions required.
+     */
+    @Nullable
+    public static UserHandle getSubscriptionUserHandle(Context context, int subId) {
+        UserHandle userHandle = null;
+        SubscriptionManager subManager =  context.getSystemService(SubscriptionManager.class);
+        if ((subManager != null) && (SubscriptionManager.isValidSubscriptionId(subId))) {
+            userHandle = subManager.getSubscriptionUserHandle(subId);
+        }
+        return userHandle;
+    }
+}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 51a7840..5f9d516 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -71,6 +71,7 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.Settings.SettingNotFoundException;
 import android.service.carrier.CarrierIdentifier;
@@ -11999,8 +12000,9 @@
     }
 
     /**
-     * Gets the default Respond Via Message application, updating the cache if there is no
-     * respond-via-message application currently configured.
+     * Get the component name of the default app to direct respond-via-message intent for the
+     * user associated with this subscription, update the cache if there is no respond-via-message
+     * application currently configured for this user.
      * @return component name of the app and class to direct Respond Via Message intent to, or
      * {@code null} if the functionality is not supported.
      * @hide
@@ -12009,11 +12011,20 @@
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
     @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
     public @Nullable ComponentName getAndUpdateDefaultRespondViaMessageApplication() {
-        return SmsApplication.getDefaultRespondViaMessageApplication(mContext, true);
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getDefaultRespondViaMessageApplication(getSubId(), true);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error in getAndUpdateDefaultRespondViaMessageApplication: " + e);
+        }
+        return null;
     }
 
     /**
-     * Gets the default Respond Via Message application.
+     * Get the component name of the default app to direct respond-via-message intent for the
+     * user associated with this subscription.
      * @return component name of the app and class to direct Respond Via Message intent to, or
      * {@code null} if the functionality is not supported.
      * @hide
@@ -12022,7 +12033,15 @@
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
     @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
     public @Nullable ComponentName getDefaultRespondViaMessageApplication() {
-        return SmsApplication.getDefaultRespondViaMessageApplication(mContext, false);
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getDefaultRespondViaMessageApplication(getSubId(), false);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error in getDefaultRespondViaMessageApplication: " + e);
+        }
+        return null;
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 648866b..bec8417 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -17,6 +17,7 @@
 package com.android.internal.telephony;
 
 import android.app.PendingIntent;
+import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentSender;
 import android.os.Bundle;
@@ -2612,4 +2613,14 @@
      * @hide
      */
     boolean isRemovableEsimDefaultEuicc(String callingPackage);
+
+     /**
+      * Get the component name of the default app to direct respond-via-message intent for the
+      * user associated with this subscription, update the cache if there is no respond-via-message
+      * application currently configured for this user.
+      * @return component name of the app and class to direct Respond Via Message intent to, or
+      * {@code null} if the functionality is not supported.
+      * @hide
+      */
+      ComponentName getDefaultRespondViaMessageApplication(int subId, boolean updateIfNeeded);
 }
diff --git a/tests/TelephonyCommonTests/Android.bp b/tests/TelephonyCommonTests/Android.bp
index a9fbfd9..81ec265 100644
--- a/tests/TelephonyCommonTests/Android.bp
+++ b/tests/TelephonyCommonTests/Android.bp
@@ -47,7 +47,7 @@
 
     // Uncomment this and comment out the jarjar rule if you want to attach a debugger and step
     // through the renamed classes.
-    // platform_apis: true,
+    platform_apis: true,
 
     libs: [
         "android.test.runner",
diff --git a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
index 7a2af72..adefac6 100644
--- a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
+++ b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
@@ -44,6 +44,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.UserHandle;
@@ -75,9 +76,12 @@
 public class SmsApplicationTest {
     private static final ComponentName TEST_COMPONENT_NAME =
             ComponentName.unflattenFromString("com.android.test/.TestSmsApp");
+    public static final String BLUETOOTH_PACKAGE_NAME = "com.android.bluetooth.services";
     private static final String MMS_RECEIVER_NAME = "TestMmsReceiver";
     private static final String RESPOND_VIA_SMS_NAME = "TestRespondViaSmsHandler";
     private static final String SEND_TO_NAME = "TestSendTo";
+    private static final String EXTERNAL_PROVIDER_CHANGE_NAME = "TestExternalProviderChangeHandler";
+    private static final String SIM_FULL_NAME = "TestSimFullHandler";
     private static final int SMS_APP_UID = 10001;
 
     private static final int FAKE_PHONE_UID = 10002;
@@ -102,6 +106,7 @@
     }).collect(Collectors.toSet());
 
     @Mock private Context mContext;
+    @Mock private Resources mResources;
     @Mock private TelephonyManager mTelephonyManager;
     @Mock private RoleManager mRoleManager;
     @Mock private PackageManager mPackageManager;
@@ -118,6 +123,9 @@
         when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
         when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOpsManager);
         when(mContext.createContextAsUser(isNotNull(), anyInt())).thenReturn(mContext);
+        when(mContext.getResources()).thenReturn(mResources);
+        when(mResources.getString(eq(com.android.internal.R.string.config_systemBluetoothStack)))
+                .thenReturn(BLUETOOTH_PACKAGE_NAME);
 
         doAnswer(invocation -> getResolveInfosForIntent(invocation.getArgument(0)))
                 .when(mPackageManager)
@@ -146,24 +154,46 @@
         }
     }
 
+
     @Test
-    public void testGetDefaultSmsApplication() {
+    public void testGetDefaultSmsApplicationAsUser() {
         assertEquals(TEST_COMPONENT_NAME,
-                SmsApplication.getDefaultSmsApplicationAsUser(mContext, false, 0));
+                SmsApplication.getDefaultSmsApplicationAsUser(mContext, false,
+                        UserHandle.SYSTEM));
+    }
+
+
+    @Test
+    public void testGetDefaultMmsApplicationAsUser() {
+        ComponentName componentName = SmsApplication.getDefaultMmsApplicationAsUser(mContext,
+                        false, UserHandle.SYSTEM);
+        assertEquals(TEST_COMPONENT_NAME.getPackageName(), componentName.getPackageName());
+        assertEquals(MMS_RECEIVER_NAME, componentName.getClassName());
     }
 
     @Test
-    public void testGetDefaultMmsApplication() {
-        assertEquals(TEST_COMPONENT_NAME,
-                SmsApplication.getDefaultMmsApplicationAsUser(mContext, false,
-                        UserHandle.USER_SYSTEM));
+    public void testGetDefaultExternalTelephonyProviderChangedApplicationAsUser() {
+        ComponentName componentName = SmsApplication
+                .getDefaultExternalTelephonyProviderChangedApplicationAsUser(mContext,
+                        false, UserHandle.SYSTEM);
+        assertEquals(TEST_COMPONENT_NAME.getPackageName(), componentName.getPackageName());
+        assertEquals(EXTERNAL_PROVIDER_CHANGE_NAME, componentName.getClassName());
     }
 
     @Test
-    public void testGetDefaultExternalTelephonyProviderChangedApplication() {
-        assertEquals(TEST_COMPONENT_NAME,
-                SmsApplication.getDefaultExternalTelephonyProviderChangedApplicationAsUser(mContext,
-                        false, UserHandle.USER_SYSTEM));
+    public void testGetDefaultRespondViaMessageApplicationAsUserAsUser() {
+        ComponentName componentName = SmsApplication.getDefaultRespondViaMessageApplicationAsUser(
+                mContext, false, UserHandle.SYSTEM);
+        assertEquals(TEST_COMPONENT_NAME.getPackageName(), componentName.getPackageName());
+        assertEquals(RESPOND_VIA_SMS_NAME, componentName.getClassName());
+    }
+
+    @Test
+    public void testGetDefaultSimFullApplicationAsUser() {
+        ComponentName componentName = SmsApplication.getDefaultSimFullApplicationAsUser(mContext,
+                false, UserHandle.SYSTEM);
+        assertEquals(TEST_COMPONENT_NAME.getPackageName(), componentName.getPackageName());
+        assertEquals(SIM_FULL_NAME, componentName.getClassName());
     }
 
     @Test
@@ -174,7 +204,8 @@
         setupPackageInfosForCoreApps();
 
         assertEquals(TEST_COMPONENT_NAME,
-                SmsApplication.getDefaultSmsApplicationAsUser(mContext, true, 0));
+                SmsApplication.getDefaultSmsApplicationAsUser(mContext, true,
+                        UserHandle.SYSTEM));
         verify(mAppOpsManager, atLeastOnce()).setUidMode(AppOpsManager.OPSTR_READ_SMS, SMS_APP_UID,
                 AppOpsManager.MODE_ALLOWED);
     }
@@ -251,6 +282,10 @@
                 return Collections.singletonList(makeRespondViaMessageResolveInfo());
             case Intent.ACTION_SENDTO:
                 return Collections.singletonList(makeSendToResolveInfo());
+            case Telephony.Sms.Intents.ACTION_EXTERNAL_PROVIDER_CHANGE:
+                return Collections.singletonList(makeExternalProviderChangeResolveInfo());
+            case Telephony.Sms.Intents.SIM_FULL_ACTION:
+                return Collections.singletonList(makeSimFullResolveInfo());
         }
         return Collections.emptyList();
     }
@@ -308,4 +343,26 @@
         info.activityInfo = activityInfo;
         return info;
     }
+
+    private ResolveInfo makeExternalProviderChangeResolveInfo() {
+        ResolveInfo info = new ResolveInfo();
+        ActivityInfo activityInfo = new ActivityInfo();
+
+        activityInfo.packageName = TEST_COMPONENT_NAME.getPackageName();
+        activityInfo.name = EXTERNAL_PROVIDER_CHANGE_NAME;
+
+        info.activityInfo = activityInfo;
+        return info;
+    }
+
+    private ResolveInfo makeSimFullResolveInfo() {
+        ResolveInfo info = new ResolveInfo();
+        ActivityInfo activityInfo = new ActivityInfo();
+
+        activityInfo.packageName = TEST_COMPONENT_NAME.getPackageName();
+        activityInfo.name = SIM_FULL_NAME;
+
+        info.activityInfo = activityInfo;
+        return info;
+    }
 }
diff --git a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/TelephonyUtilsTest.java b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/TelephonyUtilsTest.java
new file mode 100644
index 0000000..a62103e
--- /dev/null
+++ b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/TelephonyUtilsTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.tests;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.telephony.SubscriptionManager;
+
+import com.android.internal.telephony.util.TelephonyUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+public class TelephonyUtilsTest {
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
+
+    // Mocked classes
+    @Mock
+    private Context mContext;
+    @Mock
+    private SubscriptionManager mSubscriptionManager;
+
+    @Before
+    public void setup() {
+        doReturn(mSubscriptionManager).when(mContext)
+                .getSystemService(eq(SubscriptionManager.class));
+    }
+
+
+    @Test
+    public void getSubscriptionUserHandle_subId_invalid() {
+        int invalidSubId = -10;
+        doReturn(false).when(mSubscriptionManager).isActiveSubscriptionId(eq(invalidSubId));
+
+        TelephonyUtils.getSubscriptionUserHandle(mContext, invalidSubId);
+
+        // getSubscriptionUserHandle should not be called if subID is inactive.
+        verify(mSubscriptionManager, never()).getSubscriptionUserHandle(eq(invalidSubId));
+    }
+
+    @Test
+    public void getSubscriptionUserHandle_subId_valid() {
+        int activeSubId = 1;
+        doReturn(true).when(mSubscriptionManager).isActiveSubscriptionId(eq(activeSubId));
+
+        TelephonyUtils.getSubscriptionUserHandle(mContext, activeSubId);
+
+        // getSubscriptionUserHandle should be called if subID is active.
+        verify(mSubscriptionManager, times(1)).getSubscriptionUserHandle(eq(activeSubId));
+    }
+}
+
+