Merge "Add support for LTE VoPS info"
diff --git a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index 0617f56..e85db77 100644
--- a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -23,6 +23,7 @@
 import android.os.ServiceManager;
 import android.telephony.CellInfo;
 import android.telephony.CellLocation;
+import android.telephony.DataFailCause;
 import android.telephony.PhoneCapability;
 import android.telephony.PhysicalChannelConfig;
 import android.telephony.PreciseCallState;
@@ -286,7 +287,7 @@
     }
 
     public void notifyPreciseDataConnectionFailed(Phone sender, String apnType,
-            String apn, String failCause) {
+            String apn, @DataFailCause.FailCause int failCause) {
         // FIXME: subId?
         try {
             mRegistry.notifyPreciseDataConnectionFailed(apnType, apn, failCause);
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index 5e08a0c..9ca77b4 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -46,6 +46,7 @@
 import android.telephony.CellInfo;
 import android.telephony.CellLocation;
 import android.telephony.ClientRequestStats;
+import android.telephony.DataFailCause;
 import android.telephony.ImsiEncryptionInfo;
 import android.telephony.PhoneStateListener;
 import android.telephony.PhysicalChannelConfig;
@@ -3096,7 +3097,7 @@
     }
 
     public void notifyPreciseDataConnectionFailed(String apnType, String apn,
-            String failCause) {
+            @DataFailCause.FailCause int failCause) {
         mNotifier.notifyPreciseDataConnectionFailed(this, apnType, apn, failCause);
     }
 
diff --git a/src/java/com/android/internal/telephony/PhoneNotifier.java b/src/java/com/android/internal/telephony/PhoneNotifier.java
index 397aff7..ce03ad8 100644
--- a/src/java/com/android/internal/telephony/PhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/PhoneNotifier.java
@@ -18,6 +18,7 @@
 
 import android.telephony.CellInfo;
 import android.telephony.CellLocation;
+import android.telephony.DataFailCause;
 import android.telephony.PhoneCapability;
 import android.telephony.PhysicalChannelConfig;
 import android.telephony.TelephonyManager;
@@ -59,8 +60,8 @@
 
     void notifyDisconnectCause(int cause, int preciseCause);
 
-    void notifyPreciseDataConnectionFailed(Phone sender, String apnType, String apn,
-                                                  String failCause);
+    public void notifyPreciseDataConnectionFailed(Phone sender, String apnType, String apn,
+                                                  @DataFailCause.FailCause int failCause);
 
     /** send a notification that the SRVCC state has changed.*/
     void notifySrvccStateChanged(Phone sender, @TelephonyManager.SrvccState int state);
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 42bb55a..41081e6 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -2452,10 +2452,21 @@
             mPreferredNetworkType = networkType;
             mMetrics.writeSetPreferredNetworkType(mPhoneId, networkType);
 
-            try {
-                radioProxy.setPreferredNetworkType(rr.mSerial, networkType);
-            } catch (RemoteException | RuntimeException e) {
-                handleRadioProxyExceptionForRR(rr, "setPreferredNetworkType", e);
+            if (mRadioVersion.lessOrEqual(RADIO_HAL_VERSION_1_3)) {
+                try {
+                    radioProxy.setPreferredNetworkType(rr.mSerial, networkType);
+                } catch (RemoteException | RuntimeException e) {
+                    handleRadioProxyExceptionForRR(rr, "setPreferredNetworkType", e);
+                }
+            } else if (mRadioVersion.equals(RADIO_HAL_VERSION_1_4)) {
+                android.hardware.radio.V1_4.IRadio radioProxy14 =
+                        (android.hardware.radio.V1_4.IRadio) radioProxy;
+                try {
+                    radioProxy14.setPreferredNetworkTypeBitmap(
+                            rr.mSerial, RadioAccessFamily.getRafFromNetworkType(networkType));
+                } catch (RemoteException | RuntimeException e) {
+                    handleRadioProxyExceptionForRR(rr, "setPreferredNetworkTypeBitmap", e);
+                }
             }
         }
     }
@@ -2466,13 +2477,21 @@
         if (radioProxy != null) {
             RILRequest rr = obtainRequest(RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, result,
                     mRILDefaultWorkSource);
-
             if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
-            try {
-                radioProxy.getPreferredNetworkType(rr.mSerial);
-            } catch (RemoteException | RuntimeException e) {
-                handleRadioProxyExceptionForRR(rr, "getPreferredNetworkType", e);
+            if (mRadioVersion.lessOrEqual(RADIO_HAL_VERSION_1_3)) {
+                try {
+                    radioProxy.getPreferredNetworkType(rr.mSerial);
+                } catch (RemoteException | RuntimeException e) {
+                    handleRadioProxyExceptionForRR(rr, "getPreferredNetworkType", e);
+                }
+            } else if (mRadioVersion.equals(RADIO_HAL_VERSION_1_4)) {
+                android.hardware.radio.V1_4.IRadio radioProxy14 =
+                        (android.hardware.radio.V1_4.IRadio) radioProxy;
+                try {
+                    radioProxy14.getPreferredNetworkTypeBitmap(rr.mSerial);
+                } catch (RemoteException | RuntimeException e) {
+                    handleRadioProxyExceptionForRR(rr, "getPreferredNetworkTypeBitmap", e);
+                }
             }
         }
     }
diff --git a/src/java/com/android/internal/telephony/RadioConfigIndication.java b/src/java/com/android/internal/telephony/RadioConfigIndication.java
index 5774bb1..39af57b 100644
--- a/src/java/com/android/internal/telephony/RadioConfigIndication.java
+++ b/src/java/com/android/internal/telephony/RadioConfigIndication.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.hardware.radio.config.V1_0.IRadioConfigIndication;
+import android.hardware.radio.config.V1_2.IRadioConfigIndication;
 import android.os.AsyncResult;
 import android.telephony.Rlog;
 
diff --git a/src/java/com/android/internal/telephony/RadioResponse.java b/src/java/com/android/internal/telephony/RadioResponse.java
index 84ed51d..7057612 100644
--- a/src/java/com/android/internal/telephony/RadioResponse.java
+++ b/src/java/com/android/internal/telephony/RadioResponse.java
@@ -42,6 +42,7 @@
 import android.telephony.ModemActivityInfo;
 import android.telephony.NeighboringCellInfo;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.RadioAccessFamily;
 import android.telephony.SignalStrength;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -745,6 +746,14 @@
     }
 
     /**
+     * Callback of setPreferredNetworkTypeBitmap defined in IRadio.hal.
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setPreferredNetworkTypeBitmapResponse(RadioResponseInfo responseInfo) {
+        responseVoid(responseInfo);
+    }
+
+    /**
      *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param nwType RadioPreferredNetworkType defined in types.hal
@@ -755,6 +764,19 @@
     }
 
     /**
+     * Callback of the getPreferredNetworkTypeBitmap defined in the IRadio.hal.
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param networkTypeBitmap a 32-bit bitmap of
+     * {@link android.telephony.TelephonyManager.NetworkTypeBitMask}.
+     */
+    public void getPreferredNetworkTypeBitmapResponse(
+            RadioResponseInfo responseInfo, int networkTypeBitmap) {
+        int networkType = RadioAccessFamily.getNetworkTypeFromRaf(networkTypeBitmap);
+        mRil.mPreferredNetworkType = networkType;
+        responseInts(responseInfo, networkType);
+    }
+
+    /**
      *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param cells Vector of neighboring radio cell information
diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java
index f6c2d86..0789c5e 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -327,6 +327,8 @@
                 SubscriptionManager.GROUP_UUID));
         boolean isMetered = cursor.getInt(cursor.getColumnIndexOrThrow(
                 SubscriptionManager.IS_METERED)) == 1;
+        int profileClass = cursor.getInt(cursor.getColumnIndexOrThrow(
+                SubscriptionManager.PROFILE_CLASS));
 
         if (VDBG) {
             String iccIdToPrint = SubscriptionInfo.givePrintableIccid(iccId);
@@ -339,7 +341,7 @@
                     + isEmbedded + " accessRules:" + Arrays.toString(accessRules)
                     + " cardId:" + cardIdToPrint + " publicCardId:" + publicCardId
                     + " isOpportunistic:" + isOpportunistic + " groupUUID:" + groupUUID
-                    + " isMetered:" + isMetered);
+                    + " isMetered:" + isMetered + " profileClass:" + profileClass);
         }
 
         // If line1number has been set to a different number, use it instead.
@@ -348,9 +350,9 @@
             number = line1Number;
         }
         return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
-                nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
-                isEmbedded, accessRules, cardId, publicCardId, isOpportunistic, groupUUID,
-                isMetered, false /* isGroupDisabled = false */, carrierId);
+            nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
+            isEmbedded, accessRules, cardId, publicCardId, isOpportunistic, groupUUID,
+            isMetered, false /* isGroupDisabled */, carrierId, profileClass);
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
index 207a07a..7611620 100644
--- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
+++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
@@ -785,6 +785,7 @@
             values.put(SubscriptionManager.IS_REMOVABLE, isRemovable);
             values.put(SubscriptionManager.DISPLAY_NAME, embeddedProfile.getNickname());
             values.put(SubscriptionManager.NAME_SOURCE, SubscriptionManager.NAME_SOURCE_USER_INPUT);
+            values.put(SubscriptionManager.PROFILE_CLASS, embeddedProfile.getProfileClass());
             hasChanges = true;
             contentResolver.update(SubscriptionManager.CONTENT_URI, values,
                     SubscriptionManager.ICC_ID + "=\"" + embeddedProfile.getIccid() + "\"", null);
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index 593945d..39b443a 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -598,24 +598,13 @@
             ApnContext apnContext = cp.mApnContext;
             if (apnContext == alreadySent) continue;
             if (reason != null) apnContext.setReason(reason);
-            Pair<ApnContext, Integer> pair =
-                    new Pair<ApnContext, Integer>(apnContext, cp.mConnectionGeneration);
+            Pair<ApnContext, Integer> pair = new Pair<>(apnContext, cp.mConnectionGeneration);
             Message msg = mDct.obtainMessage(event, pair);
             AsyncResult.forMessage(msg);
             msg.sendToTarget();
         }
     }
 
-    private void notifyAllOfConnected(String reason) {
-        notifyAllWithEvent(null, DctConstants.EVENT_DATA_SETUP_COMPLETE, reason);
-    }
-
-    private void notifyAllDisconnectCompleted(@DataFailCause.FailCause int cause) {
-        notifyAllWithEvent(null, DctConstants.EVENT_DISCONNECT_DONE,
-                DataFailCause.toString(cause));
-    }
-
-
     /**
      * Send the connectionCompletedMsg.
      *
@@ -1184,6 +1173,26 @@
                     throw new UnknownHostException("Empty dns response and no system default dns");
                 }
 
+                // set pcscf
+                if (response.getPcscfs().size() > 0) {
+                    for (String pcscf : response.getPcscfs()) {
+                        if (pcscf == null) continue;
+                        pcscf = pcscf.trim();
+                        if (pcscf.isEmpty()) continue;
+                        InetAddress ia;
+                        try {
+                            ia = NetworkUtils.numericToInetAddress(pcscf);
+                        } catch (IllegalArgumentException e) {
+                            throw new UnknownHostException("Non-numeric pcscf addr=" + pcscf);
+                        }
+                        if (!ia.isAnyLocalAddress()) {
+                            linkProperties.addPcscfServer(ia);
+                        } else {
+                            log("bad address in PCSCF");
+                        }
+                    }
+                }
+
                 for (InetAddress gateway : response.getGateways()) {
                     // Allow 0.0.0.0 or :: as a gateway;
                     // this indicates a point-to-point interface.
@@ -1487,7 +1496,8 @@
                     log("DcInactiveState: enter notifyAllDisconnectCompleted failCause="
                             + mDcFailCause);
                 }
-                notifyAllDisconnectCompleted(mDcFailCause);
+                notifyAllWithEvent(null, DctConstants.EVENT_DISCONNECT_DONE,
+                        DataFailCause.toString(mDcFailCause));
             }
 
             // Remove ourselves from cid mapping, before clearSettings
@@ -1685,7 +1695,8 @@
             updateNetworkInfo();
 
             // If we were retrying there maybe more than one, otherwise they'll only be one.
-            notifyAllOfConnected(Phone.REASON_CONNECTED);
+            notifyAllWithEvent(null, DctConstants.EVENT_DATA_SETUP_COMPLETE,
+                    Phone.REASON_CONNECTED);
 
             mPhone.getCallTracker().registerForVoiceCallStarted(getHandler(),
                     DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED, null);
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index 185a6bb..f414a61 100755
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -2571,15 +2571,8 @@
      * A SETUP (aka bringUp) has completed, possibly with an error. If
      * there is an error this method will call {@link #onDataSetupCompleteError}.
      */
-    private void onDataSetupComplete(AsyncResult ar) {
-
-        int cause = DataFailCause.UNKNOWN;
-        boolean handleError = false;
-        ApnContext apnContext = getValidApnContext(ar, "onDataSetupComplete");
-
-        if (apnContext == null) return;
-
-        if (ar.exception == null) {
+    private void onDataSetupComplete(ApnContext apnContext, boolean success, int cause) {
+        if (success) {
             DataConnection dataConnection = apnContext.getDataConnection();
 
             if (RADIO_TESTS) {
@@ -2602,8 +2595,7 @@
             }
             if (dataConnection == null) {
                 log("onDataSetupComplete: no connection to DC, handle as error");
-                cause = DataFailCause.CONNECTION_TO_DATACONNECTIONAC_BROKEN;
-                handleError = true;
+                onDataSetupCompleteError(apnContext);
             } else {
                 ApnSetting apn = apnContext.getApnSetting();
                 if (DBG) {
@@ -2714,7 +2706,6 @@
                 }
             }
         } else {
-            cause = (int) (ar.result);
             if (DBG) {
                 ApnSetting apn = apnContext.getApnSetting();
                 log(String.format("onDataSetupComplete: error apn=%s cause=%s",
@@ -2727,8 +2718,9 @@
                         cause, cid, mTelephonyManager.getNetworkType());
             }
             ApnSetting apn = apnContext.getApnSetting();
-            mPhone.notifyPreciseDataConnectionFailed(apnContext.getApnType(),
-                    apn != null ? apn.getApnName() : "unknown", cause + "");
+            mPhone.notifyPreciseDataConnectionFailed(
+                    apnContext.getApnType(), apn != null ? apn.getApnName()
+                    : "unknown", cause);
 
             // Compose broadcast intent send to the specific carrier signaling receivers
             Intent intent = new Intent(TelephonyIntents
@@ -2749,37 +2741,8 @@
                 log("cause = " + cause + ", mark apn as permanent failed. apn = " + apn);
                 apnContext.markApnPermanentFailed(apn);
             }
-
-            handleError = true;
+            onDataSetupCompleteError(apnContext);
         }
-
-        if (handleError) {
-            onDataSetupCompleteError(ar);
-        }
-    }
-
-    /**
-     * check for obsolete messages.  Return ApnContext if valid, null if not
-     */
-    private ApnContext getValidApnContext(AsyncResult ar, String logString) {
-        if (ar != null && ar.userObj instanceof Pair) {
-            Pair<ApnContext, Integer>pair = (Pair<ApnContext, Integer>)ar.userObj;
-            ApnContext apnContext = pair.first;
-            if (apnContext != null) {
-                final int generation = apnContext.getConnectionGeneration();
-                if (DBG) {
-                    log("getValidApnContext (" + logString + ") on " + apnContext + " got " +
-                            generation + " vs " + pair.second);
-                }
-                if (generation == pair.second) {
-                    return apnContext;
-                } else {
-                    log("ignoring obsolete " + logString);
-                    return null;
-                }
-            }
-        }
-        throw new RuntimeException(logString + ": No apnContext");
     }
 
     /**
@@ -2788,12 +2751,7 @@
      * beginning if the list is empty. Between each SETUP request there will
      * be a delay defined by {@link #getApnDelay()}.
      */
-    private void onDataSetupCompleteError(AsyncResult ar) {
-
-        ApnContext apnContext = getValidApnContext(ar, "onDataSetupCompleteError");
-
-        if (apnContext == null) return;
-
+    private void onDataSetupCompleteError(ApnContext apnContext) {
         long delay = apnContext.getDelayForNextApn(mFailFast);
 
         // Check if we need to retry or not.
@@ -2828,10 +2786,7 @@
     /**
      * Called when EVENT_DISCONNECT_DONE is received.
      */
-    private void onDisconnectDone(AsyncResult ar) {
-        ApnContext apnContext = getValidApnContext(ar, "onDisconnectDone");
-        if (apnContext == null) return;
-
+    private void onDisconnectDone(ApnContext apnContext) {
         if(DBG) log("onDisconnectDone: EVENT_DISCONNECT_DONE apnContext=" + apnContext);
         apnContext.setState(DctConstants.State.IDLE);
 
@@ -3323,6 +3278,10 @@
     public void handleMessage (Message msg) {
         if (VDBG) log("handleMessage msg=" + msg);
 
+        AsyncResult ar;
+        Pair<ApnContext, Integer> pair;
+        ApnContext apnContext;
+        int generation;
         switch (msg.what) {
             case DctConstants.EVENT_RECORDS_LOADED:
                 // If onRecordsLoadedOrSubIdChanged() is not called here, it should be called on
@@ -3380,7 +3339,7 @@
                         cleanUpAllConnectionsInternal(false, Phone.REASON_PS_RESTRICT_ENABLED);
                         mReregisterOnReconnectFailure = false;
                     }
-                    ApnContext apnContext = mApnContextsByType.get(ApnSetting.TYPE_DEFAULT);
+                    apnContext = mApnContextsByType.get(ApnSetting.TYPE_DEFAULT);
                     if (apnContext != null) {
                         apnContext.setReason(Phone.REASON_PS_RESTRICT_ENABLED);
                         trySetupData(apnContext);
@@ -3465,16 +3424,49 @@
                 break;
 
             case DctConstants.EVENT_DATA_SETUP_COMPLETE:
-                onDataSetupComplete((AsyncResult) msg.obj);
+                ar = (AsyncResult) msg.obj;
+                pair = (Pair<ApnContext, Integer>) ar.userObj;
+                apnContext = pair.first;
+                generation = pair.second;
+                if (apnContext.getConnectionGeneration() == generation) {
+                    boolean success = true;
+                    int cause = DataFailCause.UNKNOWN;
+                    if (ar.exception != null) {
+                        success = false;
+                        cause = (int) ar.result;
+                    }
+                    onDataSetupComplete(apnContext, success, cause);
+                } else {
+                    loge("EVENT_DATA_SETUP_COMPLETE: Dropped the event because generation "
+                            + "did not match.");
+                }
                 break;
 
             case DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR:
-                onDataSetupCompleteError((AsyncResult) msg.obj);
+                ar = (AsyncResult) msg.obj;
+                pair = (Pair<ApnContext, Integer>) ar.userObj;
+                apnContext = pair.first;
+                generation = pair.second;
+                if (apnContext.getConnectionGeneration() == generation) {
+                    onDataSetupCompleteError(apnContext);
+                } else {
+                    loge("EVENT_DATA_SETUP_COMPLETE_ERROR: Dropped the event because generation "
+                            + "did not match.");
+                }
                 break;
 
             case DctConstants.EVENT_DISCONNECT_DONE:
-                log("DataConnectionTracker.handleMessage: EVENT_DISCONNECT_DONE msg=" + msg);
-                onDisconnectDone((AsyncResult) msg.obj);
+                log("EVENT_DISCONNECT_DONE msg=" + msg);
+                ar = (AsyncResult) msg.obj;
+                pair = (Pair<ApnContext, Integer>) ar.userObj;
+                apnContext = pair.first;
+                generation = pair.second;
+                if (apnContext.getConnectionGeneration() == generation) {
+                    onDisconnectDone(apnContext);
+                } else {
+                    loge("EVENT_DISCONNECT_DONE: Dropped the event because generation "
+                            + "did not match.");
+                }
                 break;
 
             case DctConstants.EVENT_VOICE_CALL_STARTED:
@@ -3615,7 +3607,7 @@
                 onDataServiceBindingChanged((Boolean) ((AsyncResult) msg.obj).result);
                 break;
             case DctConstants.EVENT_DATA_ENABLED_CHANGED:
-                AsyncResult ar = (AsyncResult) msg.obj;
+                ar = (AsyncResult) msg.obj;
                 if (ar.result instanceof Pair) {
                     Pair<Boolean, Integer> p = (Pair<Boolean, Integer>) ar.result;
                     boolean enabled = p.first;
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index 1021b74..64e5350 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -46,11 +46,9 @@
 import android.telecom.ConferenceParticipant;
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
-import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.PreciseDisconnectCause;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
@@ -2350,7 +2348,7 @@
                         dialPendingMO();
                     }
                     mHoldSwitchingState = HoldSwapState.INACTIVE;
-                } else if (mPendingMO.isEmergency()) {
+                } else if (mPendingMO != null && mPendingMO.isEmergency()) {
                     // If mPendingMO is an emergency call, disconnect the call that we tried to
                     // hold.
                     mBackgroundCall.getImsCall().terminate(ImsReasonInfo.CODE_UNSPECIFIED);
diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java
index 6ed00e3..661e48a 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccController.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccController.java
@@ -603,10 +603,14 @@
             final UiccSlot slot = mUiccSlots[slotIndex];
             boolean isEuicc = slot.isEuicc();
             String eid = null;
-            String iccid = slot.getUiccCard().getIccId();
+            UiccCard card = slot.getUiccCard();
+            if (card == null) {
+                continue;
+            }
+            String iccid = card.getIccId();
             int cardId = INVALID_CARD_ID;
             if (isEuicc) {
-                eid = slot.getUiccCard().getCardId();
+                eid = card.getCardId();
                 cardId = convertToPublicCardId(eid);
             } else {
                 // leave eid null if the UICC is not embedded
diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java
index 34c9462..edcad49 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java
@@ -201,7 +201,14 @@
     }
 
     public boolean isStateUnknown() {
-        return (mCardState == null || mCardState == CardState.CARDSTATE_ABSENT) && mStateIsUnknown;
+        if (mCardState == null || mCardState == CardState.CARDSTATE_ABSENT) {
+            // mStateIsUnknown is valid only in this scenario.
+            return mStateIsUnknown;
+        }
+        // if mUiccCard is null, assume the state to be UNKNOWN for now.
+        // The state may be known but since the actual card object is not available,
+        // it is safer to return UNKNOWN.
+        return mUiccCard == null;
     }
 
     private void checkIsEuiccSupported() {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
index 10dd12b..e3e5d96 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
@@ -101,7 +101,9 @@
                     + SubscriptionManager.GROUP_UUID + " TEXT,"
                     + SubscriptionManager.IS_METERED + " INTEGER DEFAULT 1,"
                     + SubscriptionManager.ISO_COUNTRY_CODE + " TEXT,"
-                    + SubscriptionManager.CARRIER_ID + " INTEGER DEFAULT -1"
+                    + SubscriptionManager.CARRIER_ID + " INTEGER DEFAULT -1,"
+                    + SubscriptionManager.PROFILE_CLASS
+                    + " INTEGER DEFAULT " + SubscriptionManager.PROFILE_CLASS_DEFAULT
                     + ");";
         }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
index ccb3acc..a77588b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
@@ -55,7 +55,6 @@
 import com.android.internal.net.VpnProfile;
 import com.android.internal.util.AsyncChannel;
 import com.android.server.connectivity.NetworkAgentInfo;
-import com.android.server.connectivity.NetworkMonitor;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -262,7 +261,7 @@
             //notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
             //mKeepaliveTracker.handleStopAllKeepalives(nai,
             //       ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
-            nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
+            // nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
             mNetworkAgentInfos.remove(msg.replyTo);
             //updateClat(null, nai.linkProperties, nai);
             //synchronized (mNetworkForNetId) {
@@ -957,12 +956,6 @@
     }
 
     @VisibleForTesting
-    public NetworkMonitor createNetworkMonitor(Context context, Handler handler,
-            NetworkAgentInfo nai, NetworkRequest defaultRequest) {
-        throw new RuntimeException("not implemented");
-    }
-
-    @VisibleForTesting
     public NetworkRequest defaultRequest = null;
     @VisibleForTesting
     public synchronized void addDefaultRequest() {
@@ -991,5 +984,8 @@
         throw new RuntimeException("not implemented");
     }
 
-
+    @Override
+    public NetworkRequest getDefaultRequest() {
+        throw new RuntimeException("not implemented");
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
index 1c636d5..418b46c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
@@ -23,6 +23,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.telephony.CellInfo;
+import android.telephony.DataFailCause;
 import android.telephony.PhoneCapability;
 import android.telephony.PhysicalChannelConfig;
 import android.telephony.ServiceState;
@@ -378,7 +379,7 @@
 
     @Override
     public void notifyPreciseDataConnectionFailed(String apnType, String apn,
-            String failCause) {
+                                                  @DataFailCause.FailCause int failCause) {
         throw new RuntimeException("Not implemented");
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java
index e1a5be0..dfd2bba 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java
@@ -319,4 +319,29 @@
                 0);        // slotIndex
         assertEquals(uiccCardInfo, mUiccControllerUT.getAllUiccCardInfos().get(0));
     }
+
+    @Test
+    public void testGetAllUiccCardInfosNullCard() {
+        // Give UiccController a real context so it can use shared preferences
+        mUiccControllerUT.mContext = InstrumentationRegistry.getContext();
+
+        // Mock out UiccSlots
+        mUiccControllerUT.mUiccSlots[0] = mMockSlot;
+        doReturn(true).when(mMockSlot).isEuicc();
+        doReturn(null).when(mMockSlot).getUiccCard();
+
+        // simulate card status loaded so that the UiccController sets the card ID
+        IccCardStatus ics = new IccCardStatus();
+        ics.setCardState(1 /* present */);
+        ics.setUniversalPinState(3 /* disabled */);
+        ics.atr = "abcdef0123456789abcdef";
+        ics.iccid = "123451234567890";
+        ics.eid = "A1B2C3D4";
+        AsyncResult ar = new AsyncResult(null, ics, null);
+        Message msg = Message.obtain(mUiccControllerUT, EVENT_GET_ICC_STATUS_DONE, ar);
+        mUiccControllerUT.handleMessage(msg);
+
+        // assert that the getAllUiccCardInfos returns an empty list without crashing
+        assertEquals(0, mUiccControllerUT.getAllUiccCardInfos().size());
+    }
 }