Merge aosp-24Q3-ts-dev

Bug: 358400644
Merged-In: I918f6562949e32d3581bf0a69c9bfe02dce1cd3b
Change-Id: I8e89f0d5d38f094eac3d606f929ed9272b17ad32
diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java
index 30172db..010e0fe 100644
--- a/src/java/com/android/internal/telephony/data/DataNetworkController.java
+++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java
@@ -2647,7 +2647,7 @@
                         .unregisterImsRegistrationCallback(oldCallback);
             }
             log("Successfully unregistered " + DataUtils.imsFeatureToString(imsFeature)
-                    + " registration state. sudId=" + subId);
+                    + " registration state. subId=" + subId);
             mImsFeatureRegistrationCallbacks.remove(imsFeature);
         }
     }
@@ -2658,42 +2658,46 @@
      * @param subId Subscription index.
      */
     private void registerImsStateCallback(int subId) {
-        Function<Integer, ImsStateCallback> imsFeatureStateCallbackFactory =
-                imsFeature -> new ImsStateCallback() {
-                    @Override
-                    public void onUnavailable(int reason) {
-                        // Unregister registration state update when IMS service is unbound.
-                        unregisterImsFeatureRegistrationState(subId, imsFeature);
-                    }
+        if (isImsSupportedOnDevice()) {
+            Function<Integer, ImsStateCallback> imsFeatureStateCallbackFactory =
+                    imsFeature -> new ImsStateCallback() {
+                        @Override
+                        public void onUnavailable(int reason) {
+                            // Unregister registration state update when IMS service is unbound.
+                            unregisterImsFeatureRegistrationState(subId, imsFeature);
+                        }
 
-                    @Override
-                    public void onAvailable() {
-                        mImsFeaturePackageName.put(imsFeature, ImsResolver.getInstance()
-                                .getConfiguredImsServicePackageName(mPhone.getPhoneId(),
-                                        imsFeature));
-                        // Once IMS service is bound, register for registration state update.
-                        registerImsFeatureRegistrationState(subId, imsFeature);
-                    }
+                        @Override
+                        public void onAvailable() {
+                            mImsFeaturePackageName.put(imsFeature, ImsResolver.getInstance()
+                                    .getConfiguredImsServicePackageName(mPhone.getPhoneId(),
+                                            imsFeature));
+                            // Once IMS service is bound, register for registration state update.
+                            registerImsFeatureRegistrationState(subId, imsFeature);
+                        }
 
-                    @Override
-                    public void onError() {
-                    }
-                };
+                        @Override
+                        public void onError() {
+                        }
+                    };
 
-        try {
-            ImsStateCallback callback = imsFeatureStateCallbackFactory
-                    .apply(ImsFeature.FEATURE_MMTEL);
-            mImsManager.getImsMmTelManager(subId).registerImsStateCallback(this::post,
-                    callback);
-            mImsStateCallbacks.put(ImsFeature.FEATURE_MMTEL, callback);
-            log("Successfully register MMTEL state on sub " + subId);
+            try {
+                ImsStateCallback callback = imsFeatureStateCallbackFactory
+                        .apply(ImsFeature.FEATURE_MMTEL);
+                mImsManager.getImsMmTelManager(subId).registerImsStateCallback(this::post,
+                        callback);
+                mImsStateCallbacks.put(ImsFeature.FEATURE_MMTEL, callback);
+                log("Successfully register MMTEL state on sub " + subId);
 
-            callback = imsFeatureStateCallbackFactory.apply(ImsFeature.FEATURE_RCS);
-            mImsManager.getImsRcsManager(subId).registerImsStateCallback(this::post, callback);
-            mImsStateCallbacks.put(ImsFeature.FEATURE_RCS, callback);
-            log("Successfully register RCS state on sub " + subId);
-        } catch (ImsException e) {
-            loge("Exception when registering IMS state callback. " + e);
+                callback = imsFeatureStateCallbackFactory.apply(ImsFeature.FEATURE_RCS);
+                mImsManager.getImsRcsManager(subId).registerImsStateCallback(this::post, callback);
+                mImsStateCallbacks.put(ImsFeature.FEATURE_RCS, callback);
+                log("Successfully register RCS state on sub " + subId);
+            } catch (ImsException e) {
+                loge("Exception when registering IMS state callback. " + e);
+            }
+        } else {
+            log("IMS is not supported on this device, skipping registerImsStateCallback");
         }
     }
 
@@ -2703,21 +2707,33 @@
      * @param subId Subscription index.
      */
     private void unregisterImsStateCallbacks(int subId) {
-        ImsStateCallback callback = mImsStateCallbacks.get(ImsFeature.FEATURE_MMTEL);
-        if (callback != null) {
-            mImsManager.getImsMmTelManager(subId).unregisterImsStateCallback(callback);
-            mImsStateCallbacks.remove(ImsFeature.FEATURE_MMTEL);
-            log("Unregister MMTEL state on sub " + subId);
-        }
+        if (isImsSupportedOnDevice()) {
+            ImsStateCallback callback = mImsStateCallbacks.get(ImsFeature.FEATURE_MMTEL);
+            if (callback != null) {
+                mImsManager.getImsMmTelManager(subId).unregisterImsStateCallback(callback);
+                mImsStateCallbacks.remove(ImsFeature.FEATURE_MMTEL);
+                log("Unregister MMTEL state on sub " + subId);
+            }
 
-        callback = mImsStateCallbacks.get(ImsFeature.FEATURE_RCS);
-        if (callback != null) {
-            mImsManager.getImsRcsManager(subId).unregisterImsStateCallback(callback);
-            mImsStateCallbacks.remove(ImsFeature.FEATURE_RCS);
-            log("Unregister RCS state on sub " + subId);
+            callback = mImsStateCallbacks.get(ImsFeature.FEATURE_RCS);
+            if (callback != null) {
+                mImsManager.getImsRcsManager(subId).unregisterImsStateCallback(callback);
+                mImsStateCallbacks.remove(ImsFeature.FEATURE_RCS);
+                log("Unregister RCS state on sub " + subId);
+            }
+        } else {
+            log("IMS is not supported on this device, skipping unregisterImsStateCallbacks");
         }
     }
 
+    /**
+     * called to check if FEATURE_TELEPHONY_IMS feature is available
+     */
+    private boolean isImsSupportedOnDevice() {
+        return mPhone.getContext().getPackageManager()
+                .hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS);
+    }
+
     /** Called when subscription info changed. */
     private void onSubscriptionChanged() {
         if (mSubId != mPhone.getSubId()) {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
index 60dcb59..499c1f5 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
@@ -44,6 +44,7 @@
 import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
+import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
 import android.net.InetAddresses;
 import android.net.LinkAddress;
@@ -172,6 +173,7 @@
     private RegistrationCallback mMmtelRegCallback;
     private RegistrationCallback mRcsRegCallback;
     private SubscriptionInfo mMockSubInfo;
+    private PackageManager mMockPackageManager;
 
     private int mNetworkRequestId = 0;
 
@@ -863,6 +865,7 @@
         mMockedDataNetworkControllerCallback = Mockito.mock(DataNetworkControllerCallback.class);
         mMockedDataRetryManagerCallback = Mockito.mock(DataRetryManagerCallback.class);
         mMockSubInfo = Mockito.mock(SubscriptionInfo.class);
+        mMockPackageManager = Mockito.mock(PackageManager.class);
         when(mTelephonyComponentFactory.makeDataSettingsManager(any(Phone.class),
                 any(DataNetworkController.class), any(FeatureFlags.class), any(Looper.class),
                 any(DataSettingsManager.DataSettingsManagerCallback.class))).thenCallRealMethod();
@@ -892,6 +895,8 @@
         doReturn(true).when(mFeatureFlags).satelliteInternet();
         doReturn(true).when(mFeatureFlags)
                 .ignoreExistingNetworksForInternetAllowedChecking();
+        when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
+        doReturn(true).when(mMockPackageManager).hasSystemFeature(anyString());
 
         List<SubscriptionInfo> infoList = new ArrayList<>();
         infoList.add(mMockSubInfo);