Merge "Add MEDIA_TIMEOUT error for RTCP timeout"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 0028e63..545815e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -89,6 +89,7 @@
     <protected-broadcast android:name= "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED" />
     <protected-broadcast android:name= "android.telephony.action.SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED" />
     <protected-broadcast android:name= "android.telephony.action.NETWORK_COUNTRY_CHANGED" />
+    <protected-broadcast android:name= "android.telephony.action.PRIMARY_SUBSCRIPTION_LIST_CHANGED" />
 
     <!-- For Vendor Debugging in Telephony -->
     <protected-broadcast android:name="android.telephony.action.ANOMALY_REPORTED" />
@@ -119,6 +120,7 @@
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
     <uses-permission android:name="android.permission.STATUS_BAR" />
+    <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
     <uses-permission android:name="android.permission.RECEIVE_SMS" />
     <uses-permission android:name="android.permission.READ_SMS" />
     <uses-permission android:name="android.permission.WRITE_SMS" />
@@ -432,7 +434,8 @@
 
         <!-- Handler for EuiccManager's public-facing intents. -->
         <activity android:name=".euicc.EuiccUiDispatcherActivity"
-            android:theme="@android:style/Theme.NoDisplay">
+            android:theme="@android:style/Theme.NoDisplay"
+            android:permission="android.permission.MODIFY_PHONE_STATE">
             <!-- Max out priority to ensure nobody else will handle these intents. -->
             <intent-filter android:priority="1000">
                 <action android:name=
diff --git a/res/layout/emergency_dialer.xml b/res/layout/emergency_dialer.xml
index 491b661..6247379 100644
--- a/res/layout/emergency_dialer.xml
+++ b/res/layout/emergency_dialer.xml
@@ -66,25 +66,6 @@
             android:layout_gravity="bottom"
             android:orientation="vertical">
 
-            <!--Emergency dialer shortcuts implement EmergencyInfoGroup to replace
-            EmergencyActionGroup. Using a title to indicate the dialpad is emergency calls only.-->
-            <FrameLayout
-                android:id="@+id/emergency_dialpad_title_container"
-                android:layout_height="64dp"
-                android:layout_width="match_parent"
-                android:layout_marginTop="16dp"
-                android:layout_marginBottom="24dp"
-                android:visibility="gone">
-                <TextView
-                    android:id="@+id/emergency_dialpad_title"
-                    android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:layout_gravity="center"
-                    android:textStyle="bold"
-                    android:maxLines="1"
-                    android:text="@string/emergency_dialpad_title"/>
-            </FrameLayout>
-
             <!-- FrameLayout -->
             <com.android.phone.EmergencyActionGroup
                 android:id="@+id/emergency_action_group"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index e4588c2..011f7cf 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1152,8 +1152,6 @@
     <string name="emergency_information_confirm_hint">Tap again to view info</string>
     <!-- Dialog title for the "radio enable" UI for emergency calls -->
     <string name="emergency_enable_radio_dialog_title">Emergency call</string>
-    <!-- Title for the emergency dialpad UI -->
-    <string name="emergency_dialpad_title">Emergency calls only</string>
     <!-- Emergency dialer: Title of single emergency shortcut button -->
     <string name="single_emergency_number_title">Emergency number</string>
     <!-- Emergency dialer: Title of numerous emergency shortcut buttons -->
diff --git a/sip/src/com/android/services/telephony/sip/SipIncomingCallReceiver.java b/sip/src/com/android/services/telephony/sip/SipIncomingCallReceiver.java
index c754ae4..19f5882 100644
--- a/sip/src/com/android/services/telephony/sip/SipIncomingCallReceiver.java
+++ b/sip/src/com/android/services/telephony/sip/SipIncomingCallReceiver.java
@@ -25,6 +25,7 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import android.text.TextUtils;
 import android.util.Log;
 
 /**
@@ -38,6 +39,11 @@
     public void onReceive(Context context, final Intent intent) {
         String action = intent.getAction();
 
+        if (TextUtils.isEmpty(action)) {
+            log("SipIncomingCallReceiver called with no action");
+            return;
+        }
+
         if (!isRunningInSystemUser()) {
             if (VERBOSE) log("SipIncomingCallReceiver only run in system user, ignore " + action);
             return;
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 6a3e928..1ea4180 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -48,12 +48,14 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.util.LocalLog;
 import android.util.Log;
 
 import com.android.internal.telephony.ICarrierConfigLoader;
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.SubscriptionInfoUpdater;
 import com.android.internal.telephony.TelephonyPermissions;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
@@ -99,11 +101,15 @@
     private CarrierServiceConnection[] mServiceConnection;
     // Whether we have sent config change bcast for each phone id.
     private boolean[] mHasSentConfigChange;
+    // SubscriptionInfoUpdater
+    private final SubscriptionInfoUpdater mSubscriptionInfoUpdater;
 
     // Broadcast receiver for Boot intents, register intent filter in construtor.
     private final BroadcastReceiver mBootReceiver = new ConfigLoaderBroadcastReceiver();
     // Broadcast receiver for SIM and pkg intents, register intent filter in constructor.
     private final BroadcastReceiver mPackageReceiver = new ConfigLoaderBroadcastReceiver();
+    private final LocalLog mCarrierConfigLoadingLog = new LocalLog(50);
+
 
     // Message codes; see mHandler below.
     // Request from SubscriptionInfoUpdater when SIM becomes absent or error.
@@ -134,6 +140,8 @@
     private static final int EVENT_FETCH_DEFAULT_TIMEOUT = 14;
     // Fetching config timed out from a carrier app.
     private static final int EVENT_FETCH_CARRIER_TIMEOUT = 15;
+    // SubscriptionInfoUpdater has finished updating the sub for the carrier config.
+    private static final int EVENT_SUBSCRIPTION_INFO_UPDATED = 16;
 
     private static final int BIND_TIMEOUT_MILLIS = 30000;
 
@@ -178,9 +186,6 @@
                         }
                     }
 
-                    if (mConfigFromDefaultApp[phoneId] == null
-                            && mConfigFromCarrierApp[phoneId] == null) break;
-
                     mConfigFromDefaultApp[phoneId] = null;
                     mConfigFromCarrierApp[phoneId] = null;
                     mServiceConnection[phoneId] = null;
@@ -240,9 +245,11 @@
                                     BIND_TIMEOUT_MILLIS);
                         } else {
                             // Send broadcast if bind fails.
-                            broadcastConfigChangedIntent(phoneId);
+                            notifySubscriptionInfoUpdater(phoneId);
                             // TODO: We *must* call unbindService even if bindService returns false.
                             // (And possibly if SecurityException was thrown.)
+                            loge("binding to default app: "
+                                    + mPlatformCarrierConfigPackage + " fails");
                         }
                     }
                     break;
@@ -273,7 +280,7 @@
                                     if (resultCode == RESULT_ERROR || resultData == null) {
                                         // On error, abort config fetching.
                                         loge("Failed to get carrier config");
-                                        broadcastConfigChangedIntent(phoneId);
+                                        notifySubscriptionInfoUpdater(phoneId);
                                         return;
                                     }
                                     PersistableBundle config =
@@ -291,8 +298,12 @@
                         ICarrierService carrierService =
                                 ICarrierService.Stub.asInterface(conn.service);
                         carrierService.getCarrierConfig(carrierId, resultReceiver);
+                        logWithLocalLog("fetch config for default app: "
+                                + mPlatformCarrierConfigPackage
+                                + " carrierid: " + carrierId.toString());
                     } catch (RemoteException e) {
-                        loge("Failed to get carrier config: " + e.toString());
+                        loge("Failed to get carrier config from default app: " +
+                                mPlatformCarrierConfigPackage + " err: " + e.toString());
                         mContext.unbindService(conn);
                         break; // So we don't set a timeout.
                     }
@@ -310,6 +321,8 @@
                     mContext.unbindService(mServiceConnection[phoneId]);
                     removeMessages(EVENT_FETCH_DEFAULT_TIMEOUT);
                     broadcastConfigChangedIntent(phoneId);
+                    loge("bind/fetch time out from " + mPlatformCarrierConfigPackage);
+                    notifySubscriptionInfoUpdater(phoneId);
                     break;
                 }
 
@@ -326,7 +339,7 @@
                         log("Found carrier config app: " + carrierPackageName);
                         sendMessage(obtainMessage(EVENT_DO_FETCH_CARRIER, phoneId, -1));
                     } else {
-                        broadcastConfigChangedIntent(phoneId);
+                        notifySubscriptionInfoUpdater(phoneId);
                     }
                     break;
                 }
@@ -359,6 +372,8 @@
                         } else {
                             // Send broadcast if bind fails.
                             broadcastConfigChangedIntent(phoneId);
+                            loge("bind to carrier app: " + carrierPackageName + " fails");
+                            notifySubscriptionInfoUpdater(phoneId);
                         }
                     }
                     break;
@@ -388,8 +403,10 @@
                                     removeMessages(EVENT_FETCH_CARRIER_TIMEOUT);
                                     if (resultCode == RESULT_ERROR || resultData == null) {
                                         // On error, abort config fetching.
-                                        loge("Failed to get carrier config");
+                                        loge("Failed to get carrier config from carrier app: "
+                                                + getCarrierPackageForPhoneId(phoneId));
                                         broadcastConfigChangedIntent(phoneId);
+                                        notifySubscriptionInfoUpdater(phoneId);
                                         return;
                                     }
                                     PersistableBundle config =
@@ -407,6 +424,9 @@
                         ICarrierService carrierService =
                                 ICarrierService.Stub.asInterface(conn.service);
                         carrierService.getCarrierConfig(carrierId, resultReceiver);
+                        logWithLocalLog("fetch config for carrier app: "
+                                + getCarrierPackageForPhoneId(phoneId)
+                                + " carrierid: " + carrierId.toString());
                     } catch (RemoteException e) {
                         loge("Failed to get carrier config: " + e.toString());
                         mContext.unbindService(conn);
@@ -426,6 +446,8 @@
                     mContext.unbindService(mServiceConnection[phoneId]);
                     removeMessages(EVENT_FETCH_CARRIER_TIMEOUT);
                     broadcastConfigChangedIntent(phoneId);
+                    loge("bind/fetch from carrier app timeout");
+                    notifySubscriptionInfoUpdater(phoneId);
                     break;
                 }
 
@@ -437,7 +459,7 @@
                             && mServiceConnection[phoneId] == null) {
                         break;
                     }
-                    broadcastConfigChangedIntent(phoneId);
+                    notifySubscriptionInfoUpdater(phoneId);
                     break;
                 }
 
@@ -460,6 +482,10 @@
                     }
                     break;
                 }
+
+                case EVENT_SUBSCRIPTION_INFO_UPDATED:
+                    broadcastConfigChangedIntent(phoneId);
+                    break;
             }
         }
     }
@@ -498,6 +524,7 @@
         // Make this service available through ServiceManager.
         ServiceManager.addService(Context.CARRIER_CONFIG_SERVICE, this);
         log("CarrierConfigLoader has started");
+        mSubscriptionInfoUpdater = PhoneFactory.getSubscriptionInfoUpdater();
         mHandler.sendEmptyMessage(EVENT_CHECK_SYSTEM_UPDATE);
     }
 
@@ -518,6 +545,24 @@
         }
     }
 
+    private void notifySubscriptionInfoUpdater(int phoneId) {
+        String configPackagename;
+        PersistableBundle configToSend;
+        int carrierId = getSpecificCarrierIdForPhoneId(phoneId);
+        // Prefer the carrier privileged carrier app, but if there is not one, use the platform
+        // default carrier app.
+        if (mConfigFromCarrierApp[phoneId] != null) {
+            configPackagename = getCarrierPackageForPhoneId(phoneId);
+            configToSend = mConfigFromCarrierApp[phoneId];
+        } else {
+            configPackagename = mPlatformCarrierConfigPackage;
+            configToSend = mConfigFromDefaultApp[phoneId];
+        }
+        mSubscriptionInfoUpdater.updateSubscriptionByCarrierConfigAndNotifyComplete(
+                phoneId, configPackagename, configToSend,
+                mHandler.obtainMessage(EVENT_SUBSCRIPTION_INFO_UPDATED, phoneId, -1));
+    }
+
     private void broadcastConfigChangedIntent(int phoneId) {
         broadcastConfigChangedIntent(phoneId, true);
     }
@@ -525,7 +570,8 @@
     private void broadcastConfigChangedIntent(int phoneId, boolean addSubIdExtra) {
         Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
-                Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+                Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND |
+                Intent.FLAG_RECEIVER_FOREGROUND);
         // Include subId/carrier id extra only if SIM records are loaded
         TelephonyManager telephonyManager = TelephonyManager.from(mContext);
         int simApplicationState = telephonyManager.getSimApplicationState();
@@ -537,13 +583,14 @@
             intent.putExtra(TelephonyManager.EXTRA_CARRIER_ID, getCarrierIdForPhoneId(phoneId));
         }
         intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, phoneId);
+        log("Broadcast CARRIER_CONFIG_CHANGED for phone " + phoneId);
         ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
         mHasSentConfigChange[phoneId] = true;
     }
 
     /** Binds to the default or carrier config app. */
     private boolean bindToConfigPackage(String pkgName, int phoneId, int eventId) {
-        log("Binding to " + pkgName + " for phone " + phoneId);
+        logWithLocalLog("Binding to " + pkgName + " for phone " + phoneId);
         Intent carrierService = new Intent(CarrierService.CARRIER_SERVICE_INTERFACE);
         carrierService.setPackage(pkgName);
         mServiceConnection[phoneId] = new CarrierServiceConnection(phoneId, eventId);
@@ -654,7 +701,7 @@
     private void saveConfigToXml(String packageName, int phoneId, PersistableBundle config) {
         if (SubscriptionManager.getSimStateForSlotIndex(phoneId)
                 != TelephonyManager.SIM_STATE_LOADED) {
-            log("Skip save config because SIM records are not loaded.");
+            loge("Skip save config because SIM records are not loaded.");
             return;
         }
 
@@ -679,6 +726,8 @@
             return;
         }
 
+        logWithLocalLog("save config to xml, packagename: " + packageName + " phoneId: " + phoneId);
+
         FileOutputStream outFile = null;
         try {
             outFile = new FileOutputStream(
@@ -729,7 +778,7 @@
         }
         if (SubscriptionManager.getSimStateForSlotIndex(phoneId)
                 != TelephonyManager.SIM_STATE_LOADED) {
-            log("Skip restoring config because SIM records are not yet loaded.");
+            loge("Skip restoring config because SIM records are not yet loaded.");
             return null;
         }
 
@@ -755,7 +804,7 @@
                 if (event == XmlPullParser.START_TAG && TAG_VERSION.equals(parser.getName())) {
                     String savedVersion = parser.nextText();
                     if (!version.equals(savedVersion)) {
-                        log("Saved version mismatch: " + version + " vs " + savedVersion);
+                        loge("Saved version mismatch: " + version + " vs " + savedVersion);
                         break;
                     }
                 }
@@ -973,6 +1022,9 @@
             pw.println("");
             printConfig(mOverrideConfigs[i], pw, "mOverrideConfigs");
         }
+
+        pw.println("CarrierConfigLoadingLog=");
+        mCarrierConfigLoadingLog.dump(fd, pw, args);
     }
 
     private void printConfig(PersistableBundle configApp, PrintWriter pw, String name) {
@@ -1052,11 +1104,17 @@
         }
     }
 
-    private static void log(String msg) {
+    private void log(String msg) {
         Log.d(LOG_TAG, msg);
     }
 
-    private static void loge(String msg) {
+    private void logWithLocalLog(String msg) {
+        Log.d(LOG_TAG, msg);
+        mCarrierConfigLoadingLog.log(msg);
+    }
+
+    private void loge(String msg) {
         Log.e(LOG_TAG, msg);
+        mCarrierConfigLoadingLog.log(msg);
     }
 }
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index 38eb40d..812aac4 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -1111,13 +1111,6 @@
 
         mEmergencyInfoGroup.setOnConfirmClickListener(this);
 
-        // EmergencyActionGroup is replaced by EmergencyInfoGroup.
-        mEmergencyActionGroup.setVisibility(View.GONE);
-
-        // Setup dialpad title.
-        final View emergencyDialpadTitle = findViewById(R.id.emergency_dialpad_title_container);
-        emergencyDialpadTitle.setVisibility(View.VISIBLE);
-
         mEmergencyShortcutButtonList = new ArrayList<>();
         setupEmergencyCallShortcutButton();
 
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 9444c1d..722a32b 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -21,6 +21,7 @@
 import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
 
 import android.Manifest.permission;
+import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
 import android.content.ComponentName;
@@ -74,6 +75,7 @@
 import android.telephony.PhoneCapability;
 import android.telephony.PhoneNumberRange;
 import android.telephony.RadioAccessFamily;
+import android.telephony.RadioAccessSpecifier;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
@@ -82,6 +84,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyHistogram;
 import android.telephony.TelephonyManager;
+import android.telephony.TelephonyScanManager;
 import android.telephony.UiccCardInfo;
 import android.telephony.UiccSlotInfo;
 import android.telephony.UssdResponse;
@@ -832,7 +835,9 @@
                 case CMD_GET_MODEM_ACTIVITY_INFO:
                     request = (MainThreadRequest) msg.obj;
                     onCompleted = obtainMessage(EVENT_GET_MODEM_ACTIVITY_INFO_DONE, request);
-                    defaultPhone.getModemActivityInfo(onCompleted, request.workSource);
+                    if (defaultPhone != null) {
+                        defaultPhone.getModemActivityInfo(onCompleted, request.workSource);
+                    }
                     break;
 
                 case EVENT_GET_MODEM_ACTIVITY_INFO_DONE:
@@ -4423,7 +4428,6 @@
             IBinder binder, String callingPackage) {
         TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
                 mApp, subId, "requestNetworkScan");
-
         LocationAccessPolicy.LocationPermissionResult locationResult =
                 LocationAccessPolicy.checkLocationPermission(mApp,
                         new LocationAccessPolicy.LocationPermissionQuery.Builder()
@@ -4433,18 +4437,51 @@
                                 .setMethod("requestNetworkScan")
                                 .setMinSdkVersionForFine(Build.VERSION_CODES.Q)
                                 .build());
-        switch (locationResult) {
-            case DENIED_HARD:
-                throw new SecurityException("Not allowed to request network scan -- location");
-            case DENIED_SOFT:
-                return -1;
+        if (locationResult != LocationAccessPolicy.LocationPermissionResult.ALLOWED) {
+            SecurityException e = checkNetworkRequestForSanitizedLocationAccess(request);
+            if (e != null) {
+                if (locationResult == LocationAccessPolicy.LocationPermissionResult.DENIED_HARD) {
+                    throw e;
+                } else {
+                    loge(e.getMessage());
+                    return TelephonyScanManager.INVALID_SCAN_ID;
+                }
+            }
         }
-
         return mNetworkScanRequestTracker.startNetworkScan(
                 request, messenger, binder, getPhone(subId),
                 callingPackage);
     }
 
+    private SecurityException checkNetworkRequestForSanitizedLocationAccess(
+            NetworkScanRequest request) {
+        if (mApp.checkCallingOrSelfPermission(android.Manifest.permission.NETWORK_SCAN)
+                != PERMISSION_GRANTED) {
+            return new SecurityException("permission.NETWORK_SCAN is needed for network scans"
+                    + " without location access.");
+        }
+
+        if (request.getSpecifiers() != null && request.getSpecifiers().length > 0) {
+            for (RadioAccessSpecifier ras : request.getSpecifiers()) {
+                if (ras.getChannels() != null && ras.getChannels().length > 0) {
+                    return new SecurityException("Specific channels must not be"
+                            + " scanned without location access.");
+                }
+            }
+        }
+
+        List<String> allowedMccMncs =
+                NetworkScanRequestTracker.getAllowedMccMncsForLocationRestrictedScan(mApp);
+        for (String mccmnc : request.getPlmns()) {
+            if (!allowedMccMncs.contains(mccmnc)) {
+                return new SecurityException("Requested mccmnc " + mccmnc + " is not known to the"
+                        + " device and cannot be scanned for without location access.");
+            }
+        }
+
+        return null;
+    }
+
     /**
      * Stops an existing network scan with the given scanId.
      *
@@ -5264,6 +5301,20 @@
         }
     }
 
+    @Override
+    public @Nullable PhoneAccountHandle getPhoneAccountHandleForSubscriptionId(int subscriptionId) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            Phone phone = getPhone(subscriptionId);
+            if (phone == null) {
+                return null;
+            }
+            return PhoneUtils.makePstnPhoneAccountHandle(phone);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     /**
      * @return the VoWiFi calling availability.
      */
@@ -6159,11 +6210,12 @@
      */
     @Override
     public boolean isDataRoamingEnabled(int subId) {
+        mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
+                null /* message */);
+
         boolean isEnabled = false;
         final long identity = Binder.clearCallingIdentity();
         try {
-            mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
-                    null /* message */);
             Phone phone = getPhone(subId);
             isEnabled =  phone != null ? phone.getDataRoamingEnabled() : false;
         } catch (Exception e) {
@@ -6188,11 +6240,11 @@
      */
     @Override
     public void setDataRoamingEnabled(int subId, boolean isEnabled) {
+        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+                mApp, subId, "setDataRoamingEnabled");
+
         final long identity = Binder.clearCallingIdentity();
         try {
-            TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
-                    mApp, subId, "setDataRoamingEnabled");
-
             Phone phone = getPhone(subId);
             if (phone != null) {
                 phone.setDataRoamingEnabled(isEnabled);
@@ -6204,11 +6256,12 @@
 
     @Override
     public boolean isManualNetworkSelectionAllowed(int subId) {
+        TelephonyPermissions.enforeceCallingOrSelfReadPhoneStatePermissionOrCarrierPrivilege(
+                mApp, subId, "isManualNetworkSelectionAllowed");
+
         boolean isAllowed = true;
         final long identity = Binder.clearCallingIdentity();
         try {
-            TelephonyPermissions.enforeceCallingOrSelfReadPhoneStatePermissionOrCarrierPrivilege(
-                    mApp, subId, "isManualNetworkSelectionAllowed");
             Phone phone = getPhone(subId);
             if (phone != null) {
                 isAllowed = phone.isCspPlmnEnabled();
@@ -6721,6 +6774,27 @@
         }
     }
 
+    /**
+     * Whether a modem stack is enabled or not.
+     */
+    @Override
+    public boolean isModemEnabledForSlot(int slotIndex, String callingPackage) {
+        Phone phone = PhoneFactory.getPhone(slotIndex);
+        if (phone == null) return false;
+
+        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
+                mApp, phone.getSubId(), callingPackage, "isModemEnabledForSlot")) {
+            throw new SecurityException("Requires READ_PHONE_STATE permission.");
+        }
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return PhoneConfigurationManager.getInstance().getPhoneStatus(phone);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     @Override
     public void setMultiSimCarrierRestriction(boolean isMultiSimCarrierRestricted) {
         enforceModifyPermission();