Merge "Move signal strength logic from DeviceStateMonitor to SignalStrengthController"
diff --git a/OWNERS b/OWNERS
index 003cc3c..5b59a13 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,4 +1,3 @@
-amitmahajan@google.com
 breadley@google.com
 fionaxu@google.com
 jackyu@google.com
@@ -6,11 +5,11 @@
 tgunn@google.com
 jminjie@google.com
 shuoq@google.com
-nazaninb@google.com
 sarahchin@google.com
 xiaotonj@google.com
 huiwang@google.com
 jayachandranc@google.com
 chinmayd@google.com
 amruthr@google.com
+sasindran@google.com
 
diff --git a/src/java/com/android/internal/telephony/CellularNetworkService.java b/src/java/com/android/internal/telephony/CellularNetworkService.java
index 886438a..b9d5e0e 100644
--- a/src/java/com/android/internal/telephony/CellularNetworkService.java
+++ b/src/java/com/android/internal/telephony/CellularNetworkService.java
@@ -221,16 +221,12 @@
             final int domain = NetworkRegistrationInfo.DOMAIN_CS;
 
             if (result instanceof android.hardware.radio.V1_6.RegStateResult) {
-                return getNetworkRegistrationInfo1_6(
-                        domain,
-                        transportType,
+                return getNetworkRegistrationInfo1_6(domain, transportType,
                         (android.hardware.radio.V1_6.RegStateResult) result);
             }
             // 1.5 at the top so that we can do an "early exit" from the method
             else if (result instanceof android.hardware.radio.V1_5.RegStateResult) {
-                return getNetworkRegistrationInfo(
-                        domain,
-                        transportType,
+                return getNetworkRegistrationInfo(domain, transportType,
                         (android.hardware.radio.V1_5.RegStateResult) result);
             } else if (result instanceof android.hardware.radio.V1_0.VoiceRegStateResult) {
                 android.hardware.radio.V1_0.VoiceRegStateResult voiceRegState =
@@ -245,7 +241,8 @@
                 int defaultRoamingIndicator = voiceRegState.defaultRoamingIndicator;
                 List<Integer> availableServices = getAvailableServices(
                         regState, domain, emergencyOnly);
-                CellIdentity cellIdentity = CellIdentity.create(voiceRegState.cellIdentity);
+                CellIdentity cellIdentity =
+                        RILUtils.convertHalCellIdentity(voiceRegState.cellIdentity);
                 final String rplmn = getPlmnFromCellIdentity(cellIdentity);
 
                 return new NetworkRegistrationInfo(domain, transportType, regState,
@@ -265,7 +262,8 @@
                 int defaultRoamingIndicator = voiceRegState.defaultRoamingIndicator;
                 List<Integer> availableServices = getAvailableServices(
                         regState, domain, emergencyOnly);
-                CellIdentity cellIdentity = CellIdentity.create(voiceRegState.cellIdentity);
+                CellIdentity cellIdentity =
+                        RILUtils.convertHalCellIdentity(voiceRegState.cellIdentity);
                 final String rplmn = getPlmnFromCellIdentity(cellIdentity);
 
                 return new NetworkRegistrationInfo(domain, transportType, regState,
@@ -296,16 +294,12 @@
                             LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE);
 
             if (result instanceof android.hardware.radio.V1_6.RegStateResult) {
-                return getNetworkRegistrationInfo1_6(
-                        domain,
-                        transportType,
+                return getNetworkRegistrationInfo1_6(domain, transportType,
                         (android.hardware.radio.V1_6.RegStateResult) result);
             }
             // 1.5 at the top so that we can do an "early exit" from the method
             else if (result instanceof android.hardware.radio.V1_5.RegStateResult) {
-                return getNetworkRegistrationInfo(
-                        domain,
-                        transportType,
+                return getNetworkRegistrationInfo(domain, transportType,
                         (android.hardware.radio.V1_5.RegStateResult) result);
             } else if (result instanceof android.hardware.radio.V1_0.DataRegStateResult) {
                 android.hardware.radio.V1_0.DataRegStateResult dataRegState =
@@ -315,7 +309,7 @@
                 reasonForDenial = dataRegState.reasonDataDenied;
                 emergencyOnly = isEmergencyOnly(dataRegState.regState);
                 maxDataCalls = dataRegState.maxDataCalls;
-                cellIdentity = CellIdentity.create(dataRegState.cellIdentity);
+                cellIdentity = RILUtils.convertHalCellIdentity(dataRegState.cellIdentity);
             } else if (result instanceof android.hardware.radio.V1_2.DataRegStateResult) {
                 android.hardware.radio.V1_2.DataRegStateResult dataRegState =
                         (android.hardware.radio.V1_2.DataRegStateResult) result;
@@ -324,7 +318,7 @@
                 reasonForDenial = dataRegState.reasonDataDenied;
                 emergencyOnly = isEmergencyOnly(dataRegState.regState);
                 maxDataCalls = dataRegState.maxDataCalls;
-                cellIdentity = CellIdentity.create(dataRegState.cellIdentity);
+                cellIdentity = RILUtils.convertHalCellIdentity(dataRegState.cellIdentity);
             } else if (result instanceof android.hardware.radio.V1_4.DataRegStateResult) {
                 android.hardware.radio.V1_4.DataRegStateResult dataRegState =
                         (android.hardware.radio.V1_4.DataRegStateResult) result;
@@ -334,7 +328,7 @@
                 reasonForDenial = dataRegState.base.reasonDataDenied;
                 emergencyOnly = isEmergencyOnly(dataRegState.base.regState);
                 maxDataCalls = dataRegState.base.maxDataCalls;
-                cellIdentity = CellIdentity.create(dataRegState.base.cellIdentity);
+                cellIdentity = RILUtils.convertHalCellIdentity(dataRegState.base.cellIdentity);
                 android.hardware.radio.V1_4.NrIndicators nrIndicators = dataRegState.nrIndicators;
 
                 // Check for lteVopsInfo only if its initialized and RAT is EUTRAN
@@ -379,7 +373,8 @@
             final List<Integer> availableServices = getAvailableServices(
                     regState, domain, isEmergencyOnly);
             final int rejectCause = regResult.reasonForDenial;
-            final CellIdentity cellIdentity = CellIdentity.create(regResult.cellIdentity);
+            final CellIdentity cellIdentity =
+                    RILUtils.convertHalCellIdentity(regResult.cellIdentity);
             final String rplmn = regResult.registeredPlmn;
             final int reasonForDenial = regResult.reasonForDenial;
 
@@ -459,7 +454,8 @@
             final List<Integer> availableServices = getAvailableServices(
                     regState, domain, isEmergencyOnly);
             final int rejectCause = regResult.reasonForDenial;
-            final CellIdentity cellIdentity = CellIdentity.create(regResult.cellIdentity);
+            final CellIdentity cellIdentity =
+                    RILUtils.convertHalCellIdentity(regResult.cellIdentity);
             final String rplmn = regResult.registeredPlmn;
             final int reasonForDenial = regResult.reasonForDenial;
 
diff --git a/src/java/com/android/internal/telephony/DataIndication.java b/src/java/com/android/internal/telephony/DataIndication.java
index 9da1e7c..e56cd85 100644
--- a/src/java/com/android/internal/telephony/DataIndication.java
+++ b/src/java/com/android/internal/telephony/DataIndication.java
@@ -35,18 +35,18 @@
  * Interface declaring unsolicited radio indications for data APIs.
  */
 public class DataIndication extends IRadioDataIndication.Stub {
-    RIL mRil;
+    private final RIL mRil;
 
-    DataIndication(RIL ril) {
+    public DataIndication(RIL ril) {
         mRil = ril;
     }
 
     /**
      * Indicates data call contexts have changed.
-     * @param indicationType RadioIndicationType
+     * @param indicationType Type of radio indication
      * @param dcList List of SetupDataCallResult identical to that returned by getDataCallList.
-     *               It is the complete list of current data contexts including new contexts that
-     *               have been activated.
+     *        It is the complete list of current data contexts including new contexts that have
+     *        been activated.
      */
     public void dataCallListChanged(int indicationType,
             android.hardware.radio.data.SetupDataCallResult[] dcList) {
@@ -60,7 +60,7 @@
 
     /**
      * Indicates a status update for an ongoing Keepalive session.
-     * @param indicationType RadioIndicationType
+     * @param indicationType Type of radio indication
      * @param halStatus Status of the ongoing Keepalive session
      */
     public void keepaliveStatus(int indicationType,
@@ -68,8 +68,8 @@
         mRil.processIndication(indicationType);
 
         if (RIL.RILJ_LOGD) {
-            mRil.unsljLogRet(RIL_UNSOL_KEEPALIVE_STATUS,
-                    "handle=" + halStatus.sessionHandle + " code=" +  halStatus.code);
+            mRil.unsljLogRet(RIL_UNSOL_KEEPALIVE_STATUS, "handle=" + halStatus.sessionHandle
+                    + " code=" +  halStatus.code);
         }
 
         KeepaliveStatus ks = new KeepaliveStatus(halStatus.sessionHandle, halStatus.code);
@@ -78,7 +78,7 @@
 
     /**
      * Indicates when there is new Carrier PCO data received for a data call.
-     * @param indicationType RadioIndicationType
+     * @param indicationType Type of radio indication
      * @param pco New PcoData
      */
     public void pcoData(int indicationType, android.hardware.radio.data.PcoDataInfo pco) {
@@ -93,7 +93,7 @@
 
     /**
      * Stop throttling calls to setupDataCall for the given APN.
-     * @param indicationType RadioIndicationType
+     * @param indicationType Type of radio indication
      * @param apn APN to unthrottle
      * @throws RemoteException
      */
@@ -102,7 +102,6 @@
 
         if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_UNTHROTTLE_APN, apn);
 
-        mRil.mApnUnthrottledRegistrants.notifyRegistrants(
-                new AsyncResult(null, apn, null));
+        mRil.mApnUnthrottledRegistrants.notifyRegistrants(new AsyncResult(null, apn, null));
     }
 }
diff --git a/src/java/com/android/internal/telephony/DataResponse.java b/src/java/com/android/internal/telephony/DataResponse.java
index 1bc14df..3ff9b53 100644
--- a/src/java/com/android/internal/telephony/DataResponse.java
+++ b/src/java/com/android/internal/telephony/DataResponse.java
@@ -19,8 +19,6 @@
 import android.hardware.radio.RadioError;
 import android.hardware.radio.RadioResponseInfo;
 import android.hardware.radio.data.IRadioDataResponse;
-import android.os.AsyncResult;
-import android.os.Message;
 import android.telephony.data.DataCallResponse;
 import android.telephony.data.NetworkSlicingConfig;
 
@@ -39,30 +37,6 @@
     }
 
     /**
-     * Helper function to send response msg
-     * @param msg Response message to be sent
-     * @param ret Return object to be included in the response message
-     */
-    private static void sendMessageResponse(Message msg, Object ret) {
-        if (msg != null) {
-            AsyncResult.forMessage(msg, ret, null);
-            msg.sendToTarget();
-        }
-    }
-
-    private void responseVoid(RadioResponseInfo responseInfo) {
-        RILRequest rr = mRil.processResponse(responseInfo);
-
-        if (rr != null) {
-            Object ret = null;
-            if (responseInfo.error == RadioError.NONE) {
-                sendMessageResponse(rr.mResult, ret);
-            }
-            mRil.processResponseDone(rr, responseInfo, ret);
-        }
-    }
-
-    /**
      * Acknowledge the receipt of radio request sent to the vendor. This must be sent only for
      * radio request which take long time to respond.
      * For more details, refer https://source.android.com/devices/tech/connect/ril.html
@@ -80,7 +54,7 @@
         RILRequest rr = mRil.processResponse(responseInfo);
         if (rr != null) {
             if (responseInfo.error == RadioError.NONE) {
-                sendMessageResponse(rr.mResult, id);
+                RadioResponse.sendMessageResponse(rr.mResult, id);
             }
             mRil.processResponseDone(rr, responseInfo, id);
         }
@@ -90,20 +64,19 @@
      * @param responseInfo Response info struct containing response type, serial no. and error
      */
     public void cancelHandoverResponse(RadioResponseInfo responseInfo) {
-        responseVoid(responseInfo);
+        RadioResponse.responseVoid(mRil, responseInfo);
     }
 
     /**
      * @param responseInfo Response info struct containing response type, serial no. and error
      */
     public void deactivateDataCallResponse(RadioResponseInfo responseInfo) {
-        responseVoid(responseInfo);
+        RadioResponse.responseVoid(mRil, responseInfo);
     }
 
     /**
      * @param responseInfo Response info struct containing response type, serial no. and error
-     * @param dataCallResultList Response to get data call list as defined by setupDataCallResult in
-     *                           types.hal
+     * @param dataCallResultList Response to get data call list as defined by SetupDataCallResult
      */
     public void getDataCallListResponse(RadioResponseInfo responseInfo,
             android.hardware.radio.data.SetupDataCallResult[] dataCallResultList) {
@@ -113,7 +86,7 @@
             ArrayList<DataCallResponse> response =
                     RILUtils.convertHalDataCallResultList(dataCallResultList);
             if (responseInfo.error == RadioError.NONE) {
-                sendMessageResponse(rr.mResult, response);
+                RadioResponse.sendMessageResponse(rr.mResult, response);
             }
             mRil.processResponseDone(rr, responseInfo, response);
         }
@@ -130,7 +103,7 @@
         if (rr != null) {
             NetworkSlicingConfig ret = RILUtils.convertHalSlicingConfig(slicingConfig);
             if (responseInfo.error == RadioError.NONE) {
-                sendMessageResponse(rr.mResult, ret);
+                RadioResponse.sendMessageResponse(rr.mResult, ret);
             }
             mRil.processResponseDone(rr, responseInfo, ret);
         }
@@ -140,35 +113,35 @@
      * @param responseInfo Response info struct containing response type, serial no. and error
      */
     public void releasePduSessionIdResponse(RadioResponseInfo responseInfo) {
-        responseVoid(responseInfo);
+        RadioResponse.responseVoid(mRil, responseInfo);
     }
 
     /**
      * @param responseInfo Response info struct containing response type, serial no. and error
      */
     public void setDataAllowedResponse(RadioResponseInfo responseInfo) {
-        responseVoid(responseInfo);
+        RadioResponse.responseVoid(mRil, responseInfo);
     }
 
     /**
      * @param responseInfo Response info struct containing response type, serial no. and error
      */
     public void setDataProfileResponse(RadioResponseInfo responseInfo) {
-        responseVoid(responseInfo);
+        RadioResponse.responseVoid(mRil, responseInfo);
     }
 
     /**
      * @param responseInfo Response info struct containing response type, serial no. and error
      */
     public void setDataThrottlingResponse(RadioResponseInfo responseInfo) {
-        responseVoid(responseInfo);
+        RadioResponse.responseVoid(mRil, responseInfo);
     }
 
     /**
      * @param responseInfo Response info struct containing response type, serial no. and error
      */
     public void setInitialAttachApnResponse(RadioResponseInfo responseInfo) {
-        responseVoid(responseInfo);
+        RadioResponse.responseVoid(mRil, responseInfo);
     }
 
     /**
@@ -182,7 +155,7 @@
         if (rr != null) {
             DataCallResponse response = RILUtils.convertHalDataCallResult(setupDataCallResult);
             if (responseInfo.error == RadioError.NONE) {
-                sendMessageResponse(rr.mResult, response);
+                RadioResponse.sendMessageResponse(rr.mResult, response);
             }
             mRil.processResponseDone(rr, responseInfo, response);
         }
@@ -192,7 +165,7 @@
      * @param responseInfo Response info struct containing response type, serial no. and error
      */
     public void startHandoverResponse(RadioResponseInfo responseInfo) {
-        responseVoid(responseInfo);
+        RadioResponse.responseVoid(mRil, responseInfo);
     }
 
     /**
@@ -218,7 +191,7 @@
                     }
                     // If responseInfo.error is NONE, response function sends the response message
                     // even if result is actually an error.
-                    sendMessageResponse(rr.mResult, ret);
+                    RadioResponse.sendMessageResponse(rr.mResult, ret);
                     break;
                 case RadioError.REQUEST_NOT_SUPPORTED:
                     ret = new KeepaliveStatus(KeepaliveStatus.ERROR_UNSUPPORTED);
@@ -245,7 +218,7 @@
 
         try {
             if (responseInfo.error == RadioError.NONE) {
-                sendMessageResponse(rr.mResult, null);
+                RadioResponse.sendMessageResponse(rr.mResult, null);
             } else {
                 //TODO: Error code translation
             }
diff --git a/src/java/com/android/internal/telephony/MessagingIndication.java b/src/java/com/android/internal/telephony/MessagingIndication.java
new file mode 100644
index 0000000..528b00a
--- /dev/null
+++ b/src/java/com/android/internal/telephony/MessagingIndication.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2021 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;
+
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_USSD;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_CDMA_NEW_SMS;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_NEW_SMS;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SIM_SMS_STORAGE_FULL;
+
+import android.hardware.radio.messaging.IRadioMessagingIndication;
+import android.os.AsyncResult;
+import android.telephony.SmsMessage;
+
+import com.android.internal.telephony.uicc.IccUtils;
+
+/**
+ * Interface declaring unsolicited radio indications for messaging APIs.
+ */
+public class MessagingIndication extends IRadioMessagingIndication.Stub {
+    private final RIL mRil;
+
+    public MessagingIndication(RIL ril) {
+        mRil = ril;
+    }
+
+    /**
+     * Indicates when new CDMA SMS is received.
+     * @param indicationType Type of radio indication
+     * @param msg CdmaSmsMessage
+     */
+    public void cdmaNewSms(int indicationType,
+            android.hardware.radio.messaging.CdmaSmsMessage msg) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_CDMA_NEW_SMS);
+
+        SmsMessage sms = new SmsMessage(RILUtils.convertHalCdmaSmsMessage(msg));
+        if (mRil.mCdmaSmsRegistrant != null) {
+            mRil.mCdmaSmsRegistrant.notifyRegistrant(new AsyncResult(null, sms, null));
+        }
+    }
+
+    /**
+     * Indicates that SMS storage on the RUIM is full. Messages cannot be saved on the RUIM until
+     * space is freed.
+     * @param indicationType Type of radio indication
+     */
+    public void cdmaRuimSmsStorageFull(int indicationType) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL);
+
+        if (mRil.mIccSmsFullRegistrant != null) {
+            mRil.mIccSmsFullRegistrant.notifyRegistrant();
+        }
+    }
+
+    /**
+     * Indicates when new Broadcast SMS is received
+     * @param indicationType Type of radio indication
+     * @param data If received from GSM network, "data" is byte array of 88 bytes which indicates
+     *        each page of a CBS Message sent to the MS by the BTS as coded in 3GPP 23.041 Section
+     *        9.4.1.2. If received from UMTS network, "data" is byte array of 90 up to 1252 bytes
+     *        which contain between 1 and 15 CBS Message pages sent as one packet to the MS by the
+     *        BTS as coded in 3GPP 23.041 Section 9.4.2.2
+     */
+    public void newBroadcastSms(int indicationType, byte[] data) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) {
+            mRil.unsljLogvRet(RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS,
+                    IccUtils.bytesToHexString(data));
+        }
+
+        if (mRil.mGsmBroadcastSmsRegistrant != null) {
+            mRil.mGsmBroadcastSmsRegistrant.notifyRegistrant(new AsyncResult(null, data, null));
+        }
+    }
+
+    /**
+     * Indicates when new SMS is received.
+     * @param indicationType Type of radio indication
+     * @param pdu PDU of SMS-DELIVER represented as byte array.
+     *        The PDU starts with the SMSC address per TS 27.005 (+CMT:)
+     */
+    public void newSms(int indicationType, byte[] pdu) {
+        mRil.processIndication(indicationType);
+        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS);
+
+        SmsMessageBase smsb = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu);
+        if (mRil.mGsmSmsRegistrant != null) {
+            mRil.mGsmSmsRegistrant.notifyRegistrant(
+                    new AsyncResult(null, smsb == null ? null : new SmsMessage(smsb), null));
+        }
+    }
+
+    /**
+     * Indicates when new SMS has been stored on SIM card.
+     * @param indicationType Type of radio indication
+     * @param recordNumber Record number on the SIM
+     */
+    public void newSmsOnSim(int indicationType, int recordNumber) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM);
+
+        if (mRil.mSmsOnSimRegistrant != null) {
+            mRil.mSmsOnSimRegistrant.notifyRegistrant(new AsyncResult(null, recordNumber, null));
+        }
+    }
+
+    /**
+     * Indicates when new SMS Status Report is received.
+     * @param indicationType Type of radio indication
+     * @param pdu PDU of SMS-STATUS-REPORT represented as byte array.
+     *        The PDU starts with the SMSC address per TS 27.005 (+CMT:)
+     */
+    public void newSmsStatusReport(int indicationType, byte[] pdu) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT);
+
+        if (mRil.mSmsStatusRegistrant != null) {
+            mRil.mSmsStatusRegistrant.notifyRegistrant(new AsyncResult(null, pdu, null));
+        }
+    }
+
+    /**
+     * Indicates when a new USSD message is received. The USSD session is assumed to persist if the
+     * type code is REQUEST, otherwise the current session (if any) is assumed to have terminated.
+     * @param indicationType Type of radio indication
+     * @param ussdModeType USSD type code
+     * @param msg Message string in UTF-8, if applicable
+     */
+    public void onUssd(int indicationType, int ussdModeType, String msg) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogMore(RIL_UNSOL_ON_USSD, "" + ussdModeType);
+
+        // TODO: Clean this up with a parcelable class for better self-documentation
+        String[] resp = new String[]{"" + ussdModeType, msg};
+        if (mRil.mUSSDRegistrant != null) {
+            mRil.mUSSDRegistrant.notifyRegistrant(new AsyncResult(null, resp, null));
+        }
+    }
+
+    /**
+     * Indicates that SMS storage on the SIM is full. Sent when the network attempts to deliver a
+     * new SMS message. Messages cannot be saved on the SIM until space is freed. In particular,
+     * incoming Class 2 messages must not be stored.
+     * @param indicationType Type of radio indication
+     */
+    public void simSmsStorageFull(int indicationType) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_SIM_SMS_STORAGE_FULL);
+
+        if (mRil.mIccSmsFullRegistrant != null) {
+            mRil.mIccSmsFullRegistrant.notifyRegistrant();
+        }
+    }
+}
diff --git a/src/java/com/android/internal/telephony/MessagingResponse.java b/src/java/com/android/internal/telephony/MessagingResponse.java
new file mode 100644
index 0000000..10f1690
--- /dev/null
+++ b/src/java/com/android/internal/telephony/MessagingResponse.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2021 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;
+
+import android.hardware.radio.RadioError;
+import android.hardware.radio.RadioResponseInfo;
+import android.hardware.radio.messaging.IRadioMessagingResponse;
+
+import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
+
+import java.util.ArrayList;
+
+/**
+ * Interface declaring response functions to solicited radio requests for messaging APIs.
+ */
+public class MessagingResponse extends IRadioMessagingResponse.Stub {
+    private final RIL mRil;
+
+    public MessagingResponse(RIL ril) {
+        mRil = ril;
+    }
+
+    private void responseSms(RadioResponseInfo responseInfo,
+            android.hardware.radio.messaging.SendSmsResult sms) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            long messageId = RIL.getOutgoingSmsMessageId(rr.mResult);
+            SmsResponse ret = new SmsResponse(sms.messageRef, sms.ackPDU, sms.errorCode, messageId);
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, ret);
+            }
+            mRil.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
+    /**
+     * Acknowledge the receipt of radio request sent to the vendor. This must be sent only for
+     * radio request which take long time to respond.
+     * For more details, refer https://source.android.com/devices/tech/connect/ril.html
+     * @param serial Serial no. of the request whose acknowledgement is sent.
+     */
+    public void acknowledgeRequest(int serial) {
+        mRil.processRequestAck(serial);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void acknowledgeIncomingGsmSmsWithPduResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void acknowledgeLastIncomingCdmaSmsResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void acknowledgeLastIncomingGsmSmsResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void cancelPendingUssdResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void deleteSmsOnRuimResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void deleteSmsOnSimResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param configs Vector of CDMA broadcast SMS configs
+     */
+    public void getCdmaBroadcastConfigResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.messaging.CdmaBroadcastSmsConfigInfo[] configs) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            int[] ret;
+            int numServiceCategories = configs.length;
+            if (numServiceCategories == 0) {
+                // TODO: The logic of providing default values should not be done by this transport
+                // layer; it needs to be done by the vendor ril or application logic.
+                int numInts;
+                numInts = RILUtils.CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES
+                        * RILUtils.CDMA_BSI_NO_OF_INTS_STRUCT + 1;
+                ret = new int[numInts];
+
+                // Faking a default record for all possible records.
+                ret[0] = RILUtils.CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES;
+
+                // Loop over CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES set 'english' as
+                // default language and selection status to false for all.
+                for (int i = 1; i < numInts; i += RILUtils.CDMA_BSI_NO_OF_INTS_STRUCT) {
+                    ret[i] = i / RILUtils.CDMA_BSI_NO_OF_INTS_STRUCT;
+                    ret[i + 1] = 1;
+                    ret[i + 2] = 0;
+                }
+            } else {
+                int numInts;
+                numInts = (numServiceCategories * RILUtils.CDMA_BSI_NO_OF_INTS_STRUCT) + 1;
+                ret = new int[numInts];
+
+                ret[0] = numServiceCategories;
+                for (int i = 1, j = 0; j < configs.length;
+                        j++, i = i + RILUtils.CDMA_BSI_NO_OF_INTS_STRUCT) {
+                    ret[i] = configs[i].serviceCategory;
+                    ret[i + 1] = configs[i].language;
+                    ret[i + 2] = configs[i].selected ? 1 : 0;
+                }
+            }
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, ret);
+            }
+            mRil.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param configs Vector of GSM/WCDMA Cell broadcast SMS configs
+     */
+    public void getGsmBroadcastConfigResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.messaging.GsmBroadcastSmsConfigInfo[] configs) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            ArrayList<SmsBroadcastConfigInfo> ret = new ArrayList<>();
+            for (android.hardware.radio.messaging.GsmBroadcastSmsConfigInfo info : configs) {
+                ret.add(new SmsBroadcastConfigInfo(info.fromServiceId, info.toServiceId,
+                        info.fromCodeScheme, info.toCodeScheme, info.selected));
+            }
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, ret);
+            }
+            mRil.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param smsc Short Message Service Center address on the device
+     */
+    public void getSmscAddressResponse(RadioResponseInfo responseInfo, String smsc) {
+        RadioResponse.responseString(mRil, responseInfo, smsc);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void reportSmsMemoryStatusResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param sms Response to SMS sent as defined by SendSmsResult
+     */
+    public void sendCdmaSmsExpectMoreResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.messaging.SendSmsResult sms) {
+        responseSms(responseInfo, sms);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param sms Response to SMS sent as defined by SendSmsResult
+     */
+    public void sendCdmaSmsResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.messaging.SendSmsResult sms) {
+        responseSms(responseInfo, sms);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param sms Response to SMS sent as defined by SendSmsResult
+     */
+    public void sendImsSmsResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.messaging.SendSmsResult sms) {
+        responseSms(responseInfo, sms);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param sms Response to SMS sent as defined by SendSmsResult
+     */
+    public void sendSmsExpectMoreResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.messaging.SendSmsResult sms) {
+        responseSms(responseInfo, sms);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param sms Response to sms sent as defined by SendSmsResult
+     */
+    public void sendSmsResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.messaging.SendSmsResult sms) {
+        responseSms(responseInfo, sms);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void sendUssdResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setCdmaBroadcastActivationResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setCdmaBroadcastConfigResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setGsmBroadcastActivationResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setGsmBroadcastConfigResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setSmscAddressResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param index record index where the CDMA SMS message is stored
+     */
+    public void writeSmsToRuimResponse(RadioResponseInfo responseInfo, int index) {
+        RadioResponse.responseInts(mRil, responseInfo, index);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param index record index where the message is stored
+     */
+    public void writeSmsToSimResponse(RadioResponseInfo responseInfo, int index) {
+        RadioResponse.responseInts(mRil, responseInfo, index);
+    }
+}
diff --git a/src/java/com/android/internal/telephony/ModemIndication.java b/src/java/com/android/internal/telephony/ModemIndication.java
new file mode 100644
index 0000000..db188de
--- /dev/null
+++ b/src/java/com/android/internal/telephony/ModemIndication.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2021 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;
+
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_HARDWARE_CONFIG_CHANGED;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_MODEM_RESTART;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RADIO_CAPABILITY;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RIL_CONNECTED;
+
+import android.hardware.radio.modem.IRadioModemIndication;
+import android.os.AsyncResult;
+
+import java.util.ArrayList;
+
+/**
+ * Interface declaring unsolicited radio indications for modem APIs.
+ */
+public class ModemIndication extends IRadioModemIndication.Stub {
+    private final RIL mRil;
+
+    public ModemIndication(RIL ril) {
+        mRil = ril;
+    }
+
+    /**
+     * Indicates when the hardware configuration associated with the RILd changes.
+     * @param indicationType Type of radio indication
+     * @param configs Array of hardware configs
+     */
+    public void hardwareConfigChanged(int indicationType,
+            android.hardware.radio.modem.HardwareConfig[] configs) {
+        mRil.processIndication(indicationType);
+
+        ArrayList<HardwareConfig> response = RILUtils.convertHalHardwareConfigList(configs);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_HARDWARE_CONFIG_CHANGED, response);
+
+        mRil.mHardwareConfigChangeRegistrants.notifyRegistrants(
+                new AsyncResult(null, response, null));
+    }
+
+    /**
+     * Indicates when there is a modem reset.
+     * @param indicationType Type of radio indication
+     * @param reason The reason for the reset. It may be a crash signature if the restart was due to
+     *        a crash or some string such as "user-initiated restart" or "AT command initiated
+     *        restart" that explains the cause of the modem restart
+     */
+    public void modemReset(int indicationType, String reason) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_MODEM_RESTART, reason);
+
+        mRil.writeMetricsModemRestartEvent(reason);
+        mRil.mModemResetRegistrants.notifyRegistrants(new AsyncResult(null, reason, null));
+    }
+
+    /**
+     * Sent when setRadioCapability() completes. Returns the same RadioCapability as
+     * getRadioCapability() and is the same as the one sent by setRadioCapability().
+     * @param indicationType Type of radio indication
+     * @param radioCapability Current radio capability
+     */
+    public void radioCapabilityIndication(int indicationType,
+            android.hardware.radio.modem.RadioCapability radioCapability) {
+        mRil.processIndication(indicationType);
+
+        RadioCapability response = RILUtils.convertHalRadioCapability(radioCapability, mRil);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_RADIO_CAPABILITY, response);
+
+        mRil.mPhoneRadioCapabilityChangedRegistrants.notifyRegistrants(
+                new AsyncResult(null, response, null));
+    }
+
+    /**
+     * Indicates when radio state changes.
+     * @param indicationType Type of radio indication
+     * @param radioState Current radio state
+     */
+    public void radioStateChanged(int indicationType, int radioState) {
+        mRil.processIndication(indicationType);
+
+        int state = RILUtils.convertHalRadioState(radioState);
+        if (RIL.RILJ_LOGD) {
+            mRil.unsljLogMore(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, "radioStateChanged: "
+                    + state);
+        }
+
+        mRil.setRadioState(state, false /* forceNotifyRegistrants */);
+    }
+
+    /**
+     * Indicates the ril connects and returns the version.
+     * @param indicationType Type of radio indication
+     */
+    public void rilConnected(int indicationType) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RIL_CONNECTED);
+
+        // Initial conditions
+        mRil.setRadioPower(false, null);
+        mRil.setCdmaSubscriptionSource(mRil.mCdmaSubscription, null);
+        // TODO: This should not require a version number. Setting it to latest RIL version for now.
+        mRil.notifyRegistrantsRilConnectionChanged(15);
+    }
+}
diff --git a/src/java/com/android/internal/telephony/ModemResponse.java b/src/java/com/android/internal/telephony/ModemResponse.java
new file mode 100644
index 0000000..de6a46e
--- /dev/null
+++ b/src/java/com/android/internal/telephony/ModemResponse.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2021 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;
+
+import android.hardware.radio.RadioError;
+import android.hardware.radio.RadioResponseInfo;
+import android.hardware.radio.modem.IRadioModemResponse;
+import android.os.SystemClock;
+import android.telephony.AnomalyReporter;
+import android.telephony.ModemActivityInfo;
+
+import java.util.ArrayList;
+import java.util.UUID;
+
+/**
+ * Interface declaring response functions to solicited radio requests for modem APIs.
+ */
+public class ModemResponse extends IRadioModemResponse.Stub {
+    private final RIL mRil;
+
+    public ModemResponse(RIL ril) {
+        mRil = ril;
+    }
+
+    /**
+     * Acknowledge the receipt of radio request sent to the vendor. This must be sent only for
+     * radio request which take long time to respond.
+     * For more details, refer https://source.android.com/devices/tech/connect/ril.html
+     * @param serial Serial no. of the request whose acknowledgement is sent.
+     */
+    public void acknowledgeRequest(int serial) {
+        mRil.processRequestAck(serial);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial number and error.
+     */
+    public void enableModemResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param version String containing version string for log reporting
+     */
+    public void getBasebandVersionResponse(RadioResponseInfo responseInfo, String version) {
+        RadioResponse.responseString(mRil, responseInfo, version);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param imei IMEI if GSM subscription is available
+     * @param imeisv IMEISV if GSM subscription is available
+     * @param esn ESN if CDMA subscription is available
+     * @param meid MEID if CDMA subscription is available
+     */
+    public void getDeviceIdentityResponse(RadioResponseInfo responseInfo, String imei,
+            String imeisv, String esn, String meid) {
+        RadioResponse.responseStrings(mRil, responseInfo, imei, imeisv, esn, meid);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param config Array of HardwareConfig of the radio
+     */
+    public void getHardwareConfigResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.modem.HardwareConfig[] config) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            ArrayList<HardwareConfig> ret = RILUtils.convertHalHardwareConfigList(config);
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, ret);
+            }
+            mRil.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param activityInfo modem activity information
+     */
+    public void getModemActivityInfoResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.modem.ActivityStatsInfo activityInfo) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            ModemActivityInfo ret = null;
+            if (responseInfo.error == RadioError.NONE) {
+                final int sleepModeTimeMs = activityInfo.sleepModeTimeMs;
+                final int idleModeTimeMs = activityInfo.idleModeTimeMs;
+                int [] txModeTimeMs = new int[ModemActivityInfo.getNumTxPowerLevels()];
+                for (int i = 0; i < ModemActivityInfo.getNumTxPowerLevels(); i++) {
+                    txModeTimeMs[i] = activityInfo.txmModetimeMs[i];
+                }
+                final int rxModeTimeMs = activityInfo.rxModeTimeMs;
+                ret = new ModemActivityInfo(SystemClock.elapsedRealtime(), sleepModeTimeMs,
+                        idleModeTimeMs, txModeTimeMs, rxModeTimeMs);
+            } else {
+                ret = new ModemActivityInfo(0, 0, 0,
+                        new int[ModemActivityInfo.getNumTxPowerLevels()], 0);
+                responseInfo.error = RadioError.NONE;
+            }
+            RadioResponse.sendMessageResponse(rr.mResult, ret);
+            mRil.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param isEnabled whether the modem stack is enabled.
+     */
+    public void getModemStackStatusResponse(RadioResponseInfo responseInfo, boolean isEnabled) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, isEnabled);
+            }
+            mRil.processResponseDone(rr, responseInfo, isEnabled);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param radioCapability RadioCapability from the modem
+     */
+    public void getRadioCapabilityResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.modem.RadioCapability radioCapability) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            RadioCapability ret = RILUtils.convertHalRadioCapability(radioCapability, mRil);
+            if (responseInfo.error == RadioError.REQUEST_NOT_SUPPORTED
+                    || responseInfo.error == RadioError.GENERIC_FAILURE) {
+                // TODO: Construct the supported RAF bitmask based on preferred network bitmasks
+                ret = mRil.makeStaticRadioCapability();
+                responseInfo.error = RadioError.NONE;
+            }
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, ret);
+            }
+            mRil.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param result String containing the contents of the NV item
+     */
+    public void nvReadItemResponse(RadioResponseInfo responseInfo, String result) {
+        RadioResponse.responseString(mRil, responseInfo, result);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void nvResetConfigResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void nvWriteCdmaPrlResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void nvWriteItemResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void requestShutdownResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void sendDeviceStateResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param radioCapability RadioCapability to set
+     */
+    public void setRadioCapabilityResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.modem.RadioCapability radioCapability) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            RadioCapability ret = RILUtils.convertHalRadioCapability(radioCapability, mRil);
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, ret);
+            }
+            mRil.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error.
+     */
+    public void setRadioPowerResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+        mRil.mLastRadioPowerResult = responseInfo.error;
+        if (responseInfo.error == RadioError.RF_HARDWARE_ISSUE) {
+            AnomalyReporter.reportAnomaly(
+                    UUID.fromString(RILUtils.RADIO_POWER_FAILURE_RF_HARDWARE_ISSUE_UUID),
+                    "RF HW damaged");
+        } else if (responseInfo.error == RadioError.NO_RF_CALIBRATION_INFO) {
+            AnomalyReporter.reportAnomaly(
+                    UUID.fromString(RILUtils.RADIO_POWER_FAILURE_NO_RF_CALIBRATION_UUID),
+                    "No RF calibration data");
+        } else if (responseInfo.error != RadioError.RADIO_NOT_AVAILABLE
+                && responseInfo.error != RadioError.NONE) {
+            AnomalyReporter.reportAnomaly(
+                    UUID.fromString(RILUtils.RADIO_POWER_FAILURE_BUGREPORT_UUID),
+                    "Radio power failure");
+        }
+    }
+}
diff --git a/src/java/com/android/internal/telephony/NetworkIndication.java b/src/java/com/android/internal/telephony/NetworkIndication.java
new file mode 100644
index 0000000..3800563
--- /dev/null
+++ b/src/java/com/android/internal/telephony/NetworkIndication.java
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2021 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;
+
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CDMA_PRL_CHANGED;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CELL_INFO_LIST;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_LCEDATA_RECV;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NETWORK_SCAN_RESULT;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NITZ_TIME_RECEIVED;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESTRICTED_STATE_CHANGED;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SIGNAL_STRENGTH;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SUPP_SVC_NOTIFICATION;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_VOICE_RADIO_TECH_CHANGED;
+
+import android.hardware.radio.network.IRadioNetworkIndication;
+import android.os.AsyncResult;
+import android.sysprop.TelephonyProperties;
+import android.telephony.AnomalyReporter;
+import android.telephony.BarringInfo;
+import android.telephony.CellIdentity;
+import android.telephony.CellInfo;
+import android.telephony.LinkCapacityEstimate;
+import android.telephony.NetworkRegistrationInfo;
+import android.telephony.PhysicalChannelConfig;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.text.TextUtils;
+
+import com.android.internal.telephony.gsm.SuppServiceNotification;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * Interface declaring unsolicited radio indications for network APIs.
+ */
+public class NetworkIndication extends IRadioNetworkIndication.Stub {
+    private final RIL mRil;
+
+    public NetworkIndication(RIL ril) {
+        mRil = ril;
+    }
+
+    /**
+     * Indicate that BarringInfo has changed for the current cell and user.
+     * @param indicationType Type of radio indication
+     * @param cellIdentity the CellIdentity of the Cell
+     * @param barringInfos the updated barring information from the current cell, filtered for the
+     *        current PLMN and access class / access category.
+     */
+    public void barringInfoChanged(int indicationType,
+            android.hardware.radio.network.CellIdentity cellIdentity,
+            android.hardware.radio.network.BarringInfo[] barringInfos) {
+        mRil.processIndication(indicationType);
+
+        if (cellIdentity == null || barringInfos == null) {
+            AnomalyReporter.reportAnomaly(UUID.fromString("645b16bb-c930-4c1c-9c5d-568696542e05"),
+                    "Invalid barringInfoChanged indication");
+            mRil.riljLoge("Invalid barringInfoChanged indication");
+            return;
+        }
+
+        BarringInfo cbi = new BarringInfo(RILUtils.convertHalCellIdentity(cellIdentity),
+                RILUtils.convertHalBarringInfoList(barringInfos));
+
+        mRil.mBarringInfoChangedRegistrants.notifyRegistrants(new AsyncResult(null, cbi, null));
+    }
+
+    /**
+     * Indicates when PRL (preferred roaming list) changes.
+     * @param indicationType Type of radio indication
+     * @param version PRL version after PRL changes
+     */
+    public void cdmaPrlChanged(int indicationType, int version) {
+        mRil.processIndication(indicationType);
+
+        int[] response = new int[]{version};
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CDMA_PRL_CHANGED, response);
+
+        mRil.mCdmaPrlChangedRegistrants.notifyRegistrants(new AsyncResult(null, response, null));
+    }
+
+    /**
+     * Report all of the current cell information known to the radio.
+     * @param indicationType Type of radio indication
+     * @param records Current cell information
+     */
+    public void cellInfoList(int indicationType,
+            android.hardware.radio.network.CellInfo[] records) {
+        mRil.processIndication(indicationType);
+        ArrayList<CellInfo> response = RILUtils.convertHalCellInfoList(records);
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CELL_INFO_LIST, response);
+        mRil.mRilCellInfoListRegistrants.notifyRegistrants(new AsyncResult(null, response, null));
+    }
+
+    /**
+     * Indicates current link capacity estimate.
+     * @param indicationType Type of radio indication
+     * @param lce LinkCapacityEstimate
+     */
+    public void currentLinkCapacityEstimate(int indicationType,
+            android.hardware.radio.network.LinkCapacityEstimate lce) {
+        mRil.processIndication(indicationType);
+
+        List<LinkCapacityEstimate> response = RILUtils.convertHalLceData(lce);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_LCEDATA_RECV, response);
+
+        if (mRil.mLceInfoRegistrants != null) {
+            mRil.mLceInfoRegistrants.notifyRegistrants(new AsyncResult(null, response, null));
+        }
+    }
+
+    /**
+     * Indicates current physical channel configuration.
+     * @param indicationType Type of radio indication
+     * @param configs Vector of PhysicalChannelConfigs
+     */
+    public void currentPhysicalChannelConfigs(int indicationType,
+            android.hardware.radio.network.PhysicalChannelConfig[] configs) {
+        mRil.processIndication(indicationType);
+        List<PhysicalChannelConfig> response = new ArrayList<>(configs.length);
+        for (android.hardware.radio.network.PhysicalChannelConfig config : configs) {
+            PhysicalChannelConfig.Builder builder = new PhysicalChannelConfig.Builder();
+            switch (config.band.getTag()) {
+                case android.hardware.radio.network.PhysicalChannelConfigBand.geranBand:
+                    builder.setBand(config.band.getGeranBand());
+                    break;
+                case android.hardware.radio.network.PhysicalChannelConfigBand.utranBand:
+                    builder.setBand(config.band.getUtranBand());
+                    break;
+                case android.hardware.radio.network.PhysicalChannelConfigBand.eutranBand:
+                    builder.setBand(config.band.getEutranBand());
+                    break;
+                case android.hardware.radio.network.PhysicalChannelConfigBand.ngranBand:
+                    builder.setBand(config.band.getNgranBand());
+                    break;
+                default:
+                    mRil.riljLoge("Unsupported band type " + config.band.getTag());
+            }
+            response.add(builder.setCellConnectionStatus(
+                    RILUtils.convertHalCellConnectionStatus(config.status))
+                    .setDownlinkChannelNumber(config.downlinkChannelNumber)
+                    .setUplinkChannelNumber(config.uplinkChannelNumber)
+                    .setCellBandwidthDownlinkKhz(config.cellBandwidthDownlinkKhz)
+                    .setCellBandwidthUplinkKhz(config.cellBandwidthUplinkKhz)
+                    .setNetworkType(ServiceState.rilRadioTechnologyToNetworkType(config.rat))
+                    .setPhysicalCellId(config.physicalCellId)
+                    .setContextIds(config.contextIds)
+                    .build());
+        }
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG, response);
+
+        mRil.mPhysicalChannelConfigurationRegistrants.notifyRegistrants(
+                new AsyncResult(null, response, null));
+    }
+
+    /**
+     * Indicates current signal strength of the radio.
+     * @param indicationType Type of radio indication
+     * @param signalStrength SignalStrength information
+     */
+    public void currentSignalStrength(int indicationType,
+            android.hardware.radio.network.SignalStrength signalStrength) {
+        mRil.processIndication(indicationType);
+
+        SignalStrength ssInitial = RILUtils.convertHalSignalStrength(signalStrength);
+
+        SignalStrength ss = mRil.fixupSignalStrength10(ssInitial);
+        // Note this is set to "verbose" because it happens frequently
+        if (RIL.RILJ_LOGV) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss);
+
+        if (mRil.mSignalStrengthRegistrant != null) {
+            mRil.mSignalStrengthRegistrant.notifyRegistrant(new AsyncResult(null, ss, null));
+        }
+    }
+
+    /**
+     * Indicates when IMS registration state has changed.
+     * @param indicationType Type of radio indication
+     */
+    public void imsNetworkStateChanged(int indicationType) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED);
+
+        mRil.mImsNetworkStateChangedRegistrants.notifyRegistrants();
+    }
+
+    /**
+     * Incremental network scan results.
+     * @param indicationType Type of radio indication
+     * @param result the result of the network scan
+     */
+    public void networkScanResult(int indicationType,
+            android.hardware.radio.network.NetworkScanResult result) {
+        mRil.processIndication(indicationType);
+
+        ArrayList<CellInfo> cellInfos = RILUtils.convertHalCellInfoList(result.networkInfos);
+        NetworkScanResult nsr = new NetworkScanResult(result.status, result.error, cellInfos);
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_NETWORK_SCAN_RESULT, nsr);
+        mRil.mRilNetworkScanResultRegistrants.notifyRegistrants(new AsyncResult(null, nsr, null));
+    }
+
+    /**
+     * Indicates when either voice or data network state changed
+     * @param indicationType Type of radio indication
+     */
+    public void networkStateChanged(int indicationType) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED);
+
+        mRil.mNetworkStateRegistrants.notifyRegistrants();
+    }
+
+    /**
+     * Indicates when radio has received a NITZ time message.
+     * @param indicationType Type of radio indication
+     * @param nitzTime NITZ time string in the form "yy/mm/dd,hh:mm:ss(+/-)tz,dt"
+     * @param receivedTime milliseconds since boot that the NITZ time was received
+     */
+    public void nitzTimeReceived(int indicationType, String nitzTime, long receivedTime) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_NITZ_TIME_RECEIVED, nitzTime);
+
+        // TODO: Clean this up with a parcelable class for better self-documentation
+        Object[] result = new Object[2];
+        result[0] = nitzTime;
+        result[1] = receivedTime;
+
+        boolean ignoreNitz = TelephonyProperties.ignore_nitz().orElse(false);
+
+        if (ignoreNitz) {
+            if (RIL.RILJ_LOGD) mRil.riljLog("ignoring UNSOL_NITZ_TIME_RECEIVED");
+        } else {
+            if (mRil.mNITZTimeRegistrant != null) {
+                mRil.mNITZTimeRegistrant.notifyRegistrant(new AsyncResult(null, result, null));
+            }
+            // in case NITZ time registrant isn't registered yet, or a new registrant
+            // registers later
+            mRil.mLastNITZTimeInfo = result;
+        }
+    }
+
+    /**
+     * Indicate that a registration failure has occurred.
+     * @param cellIdentity a CellIdentity the CellIdentity of the Cell
+     * @param chosenPlmn a 5 or 6 digit alphanumeric string indicating the PLMN on which
+     *        registration failed
+     * @param domain the domain of the failed procedure: CS, PS, or both
+     * @param causeCode the primary failure cause code of the procedure
+     * @param additionalCauseCode an additional cause code if applicable
+     */
+    public void registrationFailed(int indicationType,
+            android.hardware.radio.network.CellIdentity cellIdentity, String chosenPlmn,
+            @NetworkRegistrationInfo.Domain int domain, int causeCode, int additionalCauseCode) {
+        mRil.processIndication(indicationType);
+        CellIdentity ci = RILUtils.convertHalCellIdentity(cellIdentity);
+        if (ci == null || TextUtils.isEmpty(chosenPlmn)
+                || (domain & NetworkRegistrationInfo.DOMAIN_CS_PS) == 0
+                || (domain & ~NetworkRegistrationInfo.DOMAIN_CS_PS) != 0
+                || causeCode < 0 || additionalCauseCode < 0
+                || (causeCode == Integer.MAX_VALUE && additionalCauseCode == Integer.MAX_VALUE)) {
+            AnomalyReporter.reportAnomaly(UUID.fromString("f16e5703-6105-4341-9eb3-e68189156eb4"),
+                    "Invalid registrationFailed indication");
+
+            mRil.riljLoge("Invalid registrationFailed indication");
+            return;
+        }
+
+        mRil.mRegistrationFailedRegistrant.notifyRegistrant(
+                new AsyncResult(null, new RegistrationFailedEvent(
+                        ci, chosenPlmn, domain, causeCode, additionalCauseCode), null));
+    }
+
+    /**
+     * Indicates a restricted state change (eg, for Domain Specific Access Control).
+     * @param indicationType Type of radio indication
+     * @param state Bitmask of restricted state as defined by PhoneRestrictedState
+     */
+    public void restrictedStateChanged(int indicationType, int state) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogvRet(RIL_UNSOL_RESTRICTED_STATE_CHANGED, state);
+
+        if (mRil.mRestrictedStateRegistrant != null) {
+            mRil.mRestrictedStateRegistrant.notifyRegistrant(new AsyncResult(null, state, null));
+        }
+    }
+
+    /**
+     * Reports supplementary service related notification from the network.
+     * @param indicationType Type of radio indication
+     * @param suppSvcNotification SuppSvcNotification
+     */
+    public void suppSvcNotify(int indicationType,
+            android.hardware.radio.network.SuppSvcNotification suppSvcNotification) {
+        mRil.processIndication(indicationType);
+
+        SuppServiceNotification notification = new SuppServiceNotification();
+        notification.notificationType = suppSvcNotification.isMT ? 1 : 0;
+        notification.code = suppSvcNotification.code;
+        notification.index = suppSvcNotification.index;
+        notification.type = suppSvcNotification.type;
+        notification.number = suppSvcNotification.number;
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_SUPP_SVC_NOTIFICATION, notification);
+
+        if (mRil.mSsnRegistrant != null) {
+            mRil.mSsnRegistrant.notifyRegistrant(new AsyncResult(null, notification, null));
+        }
+    }
+
+    /**
+     * Indicates that voice technology has changed. Responds with new rat.
+     * @param indicationType Type of radio indication
+     * @param rat Current new voice rat
+     */
+    public void voiceRadioTechChanged(int indicationType, int rat) {
+        mRil.processIndication(indicationType);
+
+        int[] response = new int[] {rat};
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_VOICE_RADIO_TECH_CHANGED, response);
+
+        mRil.mVoiceRadioTechChangedRegistrants.notifyRegistrants(
+                new AsyncResult(null, response, null));
+    }
+}
diff --git a/src/java/com/android/internal/telephony/NetworkResponse.java b/src/java/com/android/internal/telephony/NetworkResponse.java
new file mode 100644
index 0000000..fa82a23
--- /dev/null
+++ b/src/java/com/android/internal/telephony/NetworkResponse.java
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 2021 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;
+
+import android.content.Context;
+import android.hardware.radio.RadioError;
+import android.hardware.radio.RadioResponseInfo;
+import android.hardware.radio.network.IRadioNetworkResponse;
+import android.os.AsyncResult;
+import android.telephony.BarringInfo;
+import android.telephony.CellInfo;
+import android.telephony.LinkCapacityEstimate;
+import android.telephony.NeighboringCellInfo;
+import android.telephony.RadioAccessSpecifier;
+import android.telephony.SignalStrength;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Interface declaring response functions to solicited radio requests for network APIs.
+ */
+public class NetworkResponse extends IRadioNetworkResponse.Stub {
+    private final RIL mRil;
+
+    public NetworkResponse(RIL ril) {
+        mRil = ril;
+    }
+
+    /**
+     * Acknowledge the receipt of radio request sent to the vendor. This must be sent only for
+     * radio request which take long time to respond.
+     * For more details, refer https://source.android.com/devices/tech/connect/ril.html
+     * @param serial Serial no. of the request whose acknowledgement is sent.
+     */
+    public void acknowledgeRequest(int serial) {
+        mRil.processRequestAck(serial);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param halRadioAccessFamilyBitmap a 32-bit bitmap of RadioAccessFamily.
+     */
+    public void getAllowedNetworkTypesBitmapResponse(RadioResponseInfo responseInfo,
+            int halRadioAccessFamilyBitmap) {
+        int networkTypeBitmask = RILUtils.convertHalNetworkTypeBitMask(halRadioAccessFamilyBitmap);
+        mRil.mAllowedNetworkTypesBitmask = networkTypeBitmask;
+        RadioResponse.responseInts(mRil, responseInfo, networkTypeBitmask);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param bandModes List of RadioBandMode listing supported modes
+     */
+    public void getAvailableBandModesResponse(RadioResponseInfo responseInfo, int[] bandModes) {
+        RadioResponse.responseIntArrayList(mRil, responseInfo,
+                RILUtils.primitiveArrayToArrayList(bandModes));
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param networkInfos List of network operator information as OperatorInfos
+     */
+    public void getAvailableNetworksResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.network.OperatorInfo[] networkInfos) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            ArrayList<OperatorInfo> ret = new ArrayList<>();
+            for (android.hardware.radio.network.OperatorInfo info : networkInfos) {
+                ret.add(new OperatorInfo(info.alphaLong, info.alphaShort, info.operatorNumeric,
+                        RILUtils.convertHalOperatorStatus(info.status)));
+            }
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, ret);
+            }
+            mRil.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error.
+     * @param cellIdentity CellIdentity for the barringInfos.
+     * @param barringInfos List of BarringInfo for all the barring service types.
+     */
+    public void getBarringInfoResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.network.CellIdentity cellIdentity,
+            android.hardware.radio.network.BarringInfo[] barringInfos) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            BarringInfo bi = new BarringInfo(RILUtils.convertHalCellIdentity(cellIdentity),
+                    RILUtils.convertHalBarringInfoList(barringInfos));
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, bi);
+                // notify all registrants for the possible barring info change
+                mRil.mBarringInfoChangedRegistrants.notifyRegistrants(
+                        new AsyncResult(null, bi, null));
+            }
+            mRil.processResponseDone(rr, responseInfo, bi);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param type CdmaRoamingType defined in types.hal
+     */
+    public void getCdmaRoamingPreferenceResponse(RadioResponseInfo responseInfo, int type) {
+        RadioResponse.responseInts(mRil, responseInfo, type);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param cellInfo List of current cell information known to radio
+     */
+    public void getCellInfoListResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.network.CellInfo[] cellInfo) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            ArrayList<CellInfo> ret = RILUtils.convertHalCellInfoList(cellInfo);
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, ret);
+            }
+            mRil.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param dataRegResponse Current data registration response as defined by DataRegStateResult
+     */
+    public void getDataRegistrationStateResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.network.RegStateResult dataRegResponse) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, dataRegResponse);
+            }
+            mRil.processResponseDone(rr, responseInfo, dataRegResponse);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param isRegistered false = not registered, true = registered
+     * @param ratFamily RadioTechnologyFamily. This value is valid only if isRegistered is true.
+     */
+    public void getImsRegistrationStateResponse(RadioResponseInfo responseInfo,
+            boolean isRegistered, int ratFamily) {
+        RadioResponse.responseInts(mRil, responseInfo, isRegistered ? 1 : 0,
+                ratFamily == android.hardware.radio.RadioTechnologyFamily.THREE_GPP
+                        ? PhoneConstants.PHONE_TYPE_GSM : PhoneConstants.PHONE_TYPE_CDMA);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param cells Vector of neighboring radio cell information
+     */
+    public void getNeighboringCidsResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.network.NeighboringCell[] cells) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            ArrayList<NeighboringCellInfo> ret = new ArrayList<>();
+            int[] subId = SubscriptionManager.getSubId(mRil.mPhoneId);
+            int radioType = ((TelephonyManager) mRil.mContext.getSystemService(
+                    Context.TELEPHONY_SERVICE)).getDataNetworkType(subId[0]);
+
+            if (radioType != TelephonyManager.NETWORK_TYPE_UNKNOWN) {
+                for (android.hardware.radio.network.NeighboringCell cell : cells) {
+                    ret.add(new NeighboringCellInfo(cell.rssi, cell.cid, radioType));
+                }
+            }
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, ret);
+            }
+            mRil.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param selection false for automatic selection, true for manual selection
+     */
+    public void getNetworkSelectionModeResponse(RadioResponseInfo responseInfo, boolean selection) {
+        RadioResponse.responseInts(mRil, responseInfo, selection ? 1 : 0);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param longName is long alpha ONS or EONS or empty string if unregistered
+     * @param shortName is short alpha ONS or EONS or empty string if unregistered
+     * @param numeric is 5 or 6 digit numeric code (MCC + MNC) or empty string if unregistered
+     */
+    public void getOperatorResponse(RadioResponseInfo responseInfo, String longName,
+            String shortName, String numeric) {
+        RadioResponse.responseStrings(mRil, responseInfo, longName, shortName, numeric);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param signalStrength Current signal strength of camped/connected cells
+     */
+    public void getSignalStrengthResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.network.SignalStrength signalStrength) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            SignalStrength ret = RILUtils.convertHalSignalStrength(signalStrength);
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, ret);
+            }
+            mRil.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error.
+     * @param halSpecifiers List of RadioAccessSpecifiers that are scanned.
+     */
+    public void getSystemSelectionChannelsResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.network.RadioAccessSpecifier[] halSpecifiers) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            ArrayList<RadioAccessSpecifier> specifiers = new ArrayList<>();
+            for (android.hardware.radio.network.RadioAccessSpecifier specifier : halSpecifiers) {
+                specifiers.add(RILUtils.convertHalRadioAccessSpecifier(specifier));
+            }
+            mRil.riljLog("getSystemSelectionChannelsResponse: from HIDL: " + specifiers);
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, specifiers);
+            }
+            mRil.processResponseDone(rr, responseInfo, specifiers);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param rat Current voice RAT
+     */
+    public void getVoiceRadioTechnologyResponse(RadioResponseInfo responseInfo, int rat) {
+        RadioResponse.responseInts(mRil, responseInfo, rat);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param voiceRegResponse Current Voice registration response as defined by VoiceRegStateResult
+     */
+    public void getVoiceRegistrationStateResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.network.RegStateResult voiceRegResponse) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+        if (rr != null) {
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, voiceRegResponse);
+            }
+            mRil.processResponseDone(rr, responseInfo, voiceRegResponse);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param isEnabled Indicates whether NR dual connectivity is enabled or not, True if enabled
+     *        else false.
+     */
+    public void isNrDualConnectivityEnabledResponse(RadioResponseInfo responseInfo,
+            boolean isEnabled) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, isEnabled);
+            }
+            mRil.processResponseDone(rr, responseInfo, isEnabled);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param lceInfo LceDataInfo indicating LCE data
+     */
+    public void pullLceDataResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.network.LceDataInfo lceInfo) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            List<LinkCapacityEstimate> ret = RILUtils.convertHalLceData(lceInfo);
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, ret);
+            }
+            mRil.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setAllowedNetworkTypesBitmapResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setBandModeResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setBarringPasswordResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setCdmaRoamingPreferenceResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setCellInfoListRateResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setIndicationFilterResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setLinkCapacityReportingCriteriaResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setLocationUpdatesResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setNetworkSelectionModeAutomaticResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setNetworkSelectionModeManualResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setNrDualConnectivityStateResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setSignalStrengthReportingCriteriaResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setSuppServiceNotificationsResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial number and error.
+     */
+    public void setSystemSelectionChannelsResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void startNetworkScanResponse(RadioResponseInfo responseInfo) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+        if (rr != null) {
+            NetworkScanResult nsr = null;
+            if (responseInfo.error == RadioError.NONE) {
+                nsr = new NetworkScanResult(NetworkScanResult.SCAN_STATUS_PARTIAL,
+                        RadioError.NONE, null);
+                RadioResponse.sendMessageResponse(rr.mResult, nsr);
+            }
+            mRil.processResponseDone(rr, responseInfo, nsr);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void stopNetworkScanResponse(RadioResponseInfo responseInfo) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+        if (rr != null) {
+            NetworkScanResult nsr = null;
+            if (responseInfo.error == RadioError.NONE) {
+                nsr = new NetworkScanResult(NetworkScanResult.SCAN_STATUS_PARTIAL,
+                        RadioError.NONE, null);
+                RadioResponse.sendMessageResponse(rr.mResult, nsr);
+            }
+            mRil.processResponseDone(rr, responseInfo, nsr);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param retriesRemaining Number of retries remaining, must be equal to -1 if unknown.
+     */
+    public void supplyNetworkDepersonalizationResponse(RadioResponseInfo responseInfo,
+            int retriesRemaining) {
+        RadioResponse.responseInts(mRil, responseInfo, retriesRemaining);
+    }
+}
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 309745d..2f7a482 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -256,20 +256,20 @@
     DataResponse mDataResponse;
     DataIndication mDataIndication;
     volatile IRadioData mDataProxy = null;
-    //MessagingResponse mMessagingResponse;
-    //MessagingIndication mMessagingIndication;
+    MessagingResponse mMessagingResponse;
+    MessagingIndication mMessagingIndication;
     volatile IRadioMessaging mMessagingProxy = null;
-    //ModemResponse mModemResponse;
-    //ModemIndication mModemIndication;
+    ModemResponse mModemResponse;
+    ModemIndication mModemIndication;
     volatile IRadioModem mModemProxy = null;
-    //NetworkResponse mNetworkResponse;
-    //NetworkIndication mNetworkIndication;
+    NetworkResponse mNetworkResponse;
+    NetworkIndication mNetworkIndication;
     volatile IRadioNetwork mNetworkProxy = null;
-    //SimResponse mSimResponse;
-    //SimIndication mSimIndication;
+    SimResponse mSimResponse;
+    SimIndication mSimIndication;
     volatile IRadioSim mSimProxy = null;
-    //VoiceResponse mVoiceResponse;
-    //VoiceIndication mVoiceIndication;
+    VoiceResponse mVoiceResponse;
+    VoiceIndication mVoiceIndication;
     volatile IRadioVoice mVoiceProxy = null;
     final AtomicLong mRadioProxyCookie = new AtomicLong(0);
     final RadioProxyDeathRecipient mRadioProxyDeathRecipient;
@@ -620,6 +620,16 @@
         mRadioIndication = new RadioIndication(this);
         mDataResponse = new DataResponse(this);
         mDataIndication = new DataIndication(this);
+        mMessagingResponse = new MessagingResponse(this);
+        mMessagingIndication = new MessagingIndication(this);
+        mModemResponse = new ModemResponse(this);
+        mModemIndication = new ModemIndication(this);
+        mNetworkResponse = new NetworkResponse(this);
+        mNetworkIndication = new NetworkIndication(this);
+        mSimResponse = new SimResponse(this);
+        mSimIndication = new SimIndication(this);
+        mVoiceResponse = new VoiceResponse(this);
+        mVoiceIndication = new VoiceIndication(this);
         mRilHandler = new RilHandler();
         mRadioProxyDeathRecipient = new RadioProxyDeathRecipient();
 
@@ -5372,7 +5382,7 @@
                         android.hardware.radio.V1_6.IRadio.castFrom(radioProxy);
 
                 android.hardware.radio.V1_6.PhonebookRecordInfo pbRecordInfo =
-                        phonebookRecord.toPhonebookRecordInfo();
+                        RILUtils.convertToHalPhonebookRecordInfo(phonebookRecord);
                 try {
                      radioProxy16.updateSimPhonebookRecords(rr.mSerial, pbRecordInfo);
                 } catch (RemoteException | RuntimeException e) {
diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java
index 1326956..deb4c57 100644
--- a/src/java/com/android/internal/telephony/RILUtils.java
+++ b/src/java/com/android/internal/telephony/RILUtils.java
@@ -261,12 +261,36 @@
 import android.service.carrier.CarrierIdentifier;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.Annotation;
+import android.telephony.BarringInfo;
+import android.telephony.CellConfigLte;
+import android.telephony.CellIdentity;
+import android.telephony.CellIdentityCdma;
+import android.telephony.CellIdentityGsm;
+import android.telephony.CellIdentityLte;
+import android.telephony.CellIdentityNr;
+import android.telephony.CellIdentityTdscdma;
+import android.telephony.CellIdentityWcdma;
 import android.telephony.CellInfo;
+import android.telephony.CellInfoCdma;
+import android.telephony.CellInfoGsm;
+import android.telephony.CellInfoLte;
+import android.telephony.CellInfoNr;
+import android.telephony.CellInfoTdscdma;
+import android.telephony.CellInfoWcdma;
+import android.telephony.CellSignalStrength;
+import android.telephony.CellSignalStrengthCdma;
+import android.telephony.CellSignalStrengthGsm;
+import android.telephony.CellSignalStrengthLte;
+import android.telephony.CellSignalStrengthNr;
+import android.telephony.CellSignalStrengthTdscdma;
+import android.telephony.CellSignalStrengthWcdma;
+import android.telephony.ClosedSubscriberGroupInfo;
 import android.telephony.LinkCapacityEstimate;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.PhysicalChannelConfig;
 import android.telephony.RadioAccessSpecifier;
 import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
 import android.telephony.SignalThresholdInfo;
 import android.telephony.SmsManager;
 import android.telephony.TelephonyManager;
@@ -284,14 +308,22 @@
 import android.telephony.data.TrafficDescriptor;
 import android.telephony.data.UrspRule;
 import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.cat.ComprehensionTlv;
 import com.android.internal.telephony.cat.ComprehensionTlvTag;
+import com.android.internal.telephony.cdma.SmsMessage;
+import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
+import com.android.internal.telephony.cdma.sms.CdmaSmsSubaddress;
+import com.android.internal.telephony.cdma.sms.SmsEnvelope;
 import com.android.internal.telephony.dataconnection.KeepaliveStatus;
+import com.android.internal.telephony.uicc.AdnCapacity;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus;
 import com.android.internal.telephony.uicc.IccCardStatus;
 import com.android.internal.telephony.uicc.IccUtils;
+import com.android.internal.telephony.uicc.SimPhonebookRecord;
 import com.android.telephony.Rlog;
 
 import java.io.ByteArrayInputStream;
@@ -301,6 +333,7 @@
 import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -310,6 +343,20 @@
 public class RILUtils {
     private static final String LOG_TAG = "RILUtils";
 
+    // The number of required config values for broadcast SMS stored in RIL_CdmaBroadcastServiceInfo
+    public static final int CDMA_BSI_NO_OF_INTS_STRUCT = 3;
+    // The number of service categories for broadcast SMS
+    public static final int CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES = 31;
+
+    // Radio power failure UUIDs
+    public static final String RADIO_POWER_FAILURE_BUGREPORT_UUID =
+            "316f3801-fa21-4954-a42f-0041eada3b31";
+    public static final String RADIO_POWER_FAILURE_RF_HARDWARE_ISSUE_UUID =
+            "316f3801-fa21-4954-a42f-0041eada3b32";
+    public static final String RADIO_POWER_FAILURE_NO_RF_CALIBRATION_UUID =
+            "316f3801-fa21-4954-a42f-0041eada3b33";
+
+
     /**
      * Convert to PersoSubstate defined in radio/1.5/types.hal
      * @param persoType PersoSubState type
@@ -450,6 +497,166 @@
     }
 
     /**
+     * Convert CdmaSmsMessage defined in radio/1.0/types.hal to SmsMessage
+     * Note only primitive fields are set
+     * @param cdmaSmsMessage CdmaSmsMessage defined in radio/1.0/types.hal
+     * @return A converted SmsMessage
+     */
+    public static SmsMessage convertHalCdmaSmsMessage(
+            android.hardware.radio.V1_0.CdmaSmsMessage cdmaSmsMessage) {
+        // Note: Parcel.readByte actually reads one Int and masks to byte
+        SmsEnvelope env = new SmsEnvelope();
+        CdmaSmsAddress addr = new CdmaSmsAddress();
+        CdmaSmsSubaddress subaddr = new CdmaSmsSubaddress();
+        byte[] data;
+        byte count;
+        int countInt;
+        int addressDigitMode;
+
+        //currently not supported by the modem-lib: env.mMessageType
+        env.teleService = cdmaSmsMessage.teleserviceId;
+
+        if (cdmaSmsMessage.isServicePresent) {
+            env.messageType = SmsEnvelope.MESSAGE_TYPE_BROADCAST;
+        } else {
+            if (SmsEnvelope.TELESERVICE_NOT_SET == env.teleService) {
+                // assume type ACK
+                env.messageType = SmsEnvelope.MESSAGE_TYPE_ACKNOWLEDGE;
+            } else {
+                env.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
+            }
+        }
+        env.serviceCategory = cdmaSmsMessage.serviceCategory;
+
+        // address
+        addressDigitMode = cdmaSmsMessage.address.digitMode;
+        addr.digitMode = (byte) (0xFF & addressDigitMode);
+        addr.numberMode = (byte) (0xFF & cdmaSmsMessage.address.numberMode);
+        addr.ton = cdmaSmsMessage.address.numberType;
+        addr.numberPlan = (byte) (0xFF & cdmaSmsMessage.address.numberPlan);
+        count = (byte) cdmaSmsMessage.address.digits.size();
+        addr.numberOfDigits = count;
+        data = new byte[count];
+        for (int index = 0; index < count; index++) {
+            data[index] = cdmaSmsMessage.address.digits.get(index);
+
+            // convert the value if it is 4-bit DTMF to 8 bit
+            if (addressDigitMode == CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF) {
+                data[index] = SmsMessage.convertDtmfToAscii(data[index]);
+            }
+        }
+
+        addr.origBytes = data;
+
+        subaddr.type = cdmaSmsMessage.subAddress.subaddressType;
+        subaddr.odd = (byte) (cdmaSmsMessage.subAddress.odd ? 1 : 0);
+        count = (byte) cdmaSmsMessage.subAddress.digits.size();
+
+        if (count < 0) {
+            count = 0;
+        }
+
+        // p_cur->sSubAddress.digits[digitCount] :
+
+        data = new byte[count];
+
+        for (int index = 0; index < count; ++index) {
+            data[index] = cdmaSmsMessage.subAddress.digits.get(index);
+        }
+
+        subaddr.origBytes = data;
+
+        /* currently not supported by the modem-lib:
+            env.bearerReply
+            env.replySeqNo
+            env.errorClass
+            env.causeCode
+        */
+
+        // bearer data
+        countInt = cdmaSmsMessage.bearerData.size();
+        if (countInt < 0) {
+            countInt = 0;
+        }
+
+        data = new byte[countInt];
+        for (int index = 0; index < countInt; index++) {
+            data[index] = cdmaSmsMessage.bearerData.get(index);
+        }
+        // BD gets further decoded when accessed in SMSDispatcher
+        env.bearerData = data;
+
+        // link the filled objects to the SMS
+        env.origAddress = addr;
+        env.origSubaddress = subaddr;
+
+        SmsMessage msg = new SmsMessage(addr, env);
+
+        return msg;
+    }
+
+    /**
+     * Convert CdmaSmsMessage defined in CdmaSmsMessage.aidl to SmsMessage
+     * Note only primitive fields are set
+     * @param msg CdmaSmsMessage defined in CdmaSmsMessage.aidl
+     * @return A converted SmsMessage
+     */
+    public static SmsMessage convertHalCdmaSmsMessage(
+            android.hardware.radio.messaging.CdmaSmsMessage msg) {
+        // Note: Parcel.readByte actually reads one Int and masks to byte
+        SmsEnvelope env = new SmsEnvelope();
+        CdmaSmsAddress addr = new CdmaSmsAddress();
+        CdmaSmsSubaddress subaddr = new CdmaSmsSubaddress();
+
+        // address
+        int addressDigitMode = msg.address.digitMode;
+        addr.digitMode = (byte) (0xFF & addressDigitMode);
+        addr.numberMode = (byte) (0xFF & (msg.address.isNumberModeDataNetwork ? 1 : 0));
+        addr.ton = msg.address.numberType;
+        addr.numberPlan = (byte) (0xFF & msg.address.numberPlan);
+        addr.numberOfDigits = msg.address.digits.length;
+        byte[] data = new byte[msg.address.digits.length];
+        for (int index = 0; index < data.length; index++) {
+            data[index] = msg.address.digits[index];
+            // convert the value if it is 4-bit DTMF to 8 bit
+            if (addressDigitMode == CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF) {
+                data[index] = SmsMessage.convertDtmfToAscii(data[index]);
+            }
+        }
+        addr.origBytes = data;
+
+        // subaddress
+        subaddr.type = msg.subAddress.subaddressType;
+        subaddr.odd = (byte) (msg.subAddress.odd ? 1 : 0);
+        subaddr.origBytes = msg.subAddress.digits;
+
+        // envelope
+        // currently not supported by the modem-lib: env.bearerReply, env.replySeqNo,
+        // env.errorClass, env.causeCode, env.mMessageType
+        env.teleService = msg.teleserviceId;
+        if (msg.isServicePresent) {
+            env.messageType = SmsEnvelope.MESSAGE_TYPE_BROADCAST;
+        } else {
+            if (SmsEnvelope.TELESERVICE_NOT_SET == env.teleService) {
+                // assume type ACK
+                env.messageType = SmsEnvelope.MESSAGE_TYPE_ACKNOWLEDGE;
+            } else {
+                env.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
+            }
+        }
+        env.serviceCategory = msg.serviceCategory;
+
+        // bearer data is further decoded when accessed in SmsDispatcher
+        env.bearerData = msg.bearerData;
+
+        // link the filled objects to the SMS
+        env.origAddress = addr;
+        env.origSubaddress = subaddr;
+
+        return new SmsMessage(addr, env);
+    }
+
+    /**
      * Convert to DataProfileInfo defined in radio/1.0/types.hal
      * @param dp Data profile
      * @return The converted DataProfileInfo
@@ -662,6 +869,64 @@
     }
 
     /**
+     * Convert RadioAccessSpecifier defined in radio/1.5/types.hal to RadioAccessSpecifier
+     * @param specifier RadioAccessSpecifier defined in radio/1.5/types.hal
+     * @return The converted RadioAccessSpecifier
+     */
+    public static RadioAccessSpecifier convertHalRadioAccessSpecifier(
+            android.hardware.radio.V1_5.RadioAccessSpecifier specifier) {
+        if (specifier == null) return null;
+        ArrayList<Integer> halBands = new ArrayList<>();
+        switch (specifier.bands.getDiscriminator()) {
+            case android.hardware.radio.V1_5.RadioAccessSpecifier.Bands.hidl_discriminator
+                    .geranBands:
+                halBands = specifier.bands.geranBands();
+                break;
+            case android.hardware.radio.V1_5.RadioAccessSpecifier.Bands.hidl_discriminator
+                    .utranBands:
+                halBands = specifier.bands.utranBands();
+                break;
+            case android.hardware.radio.V1_5.RadioAccessSpecifier.Bands.hidl_discriminator
+                    .eutranBands:
+                halBands = specifier.bands.eutranBands();
+                break;
+            case android.hardware.radio.V1_5.RadioAccessSpecifier.Bands.hidl_discriminator
+                    .ngranBands:
+                halBands = specifier.bands.ngranBands();
+                break;
+        }
+        return new RadioAccessSpecifier(convertHalRadioAccessNetworks(specifier.radioAccessNetwork),
+                halBands.stream().mapToInt(Integer::intValue).toArray(),
+                specifier.channels.stream().mapToInt(Integer::intValue).toArray());
+    }
+
+    /**
+     * Convert RadioAccessSpecifier defined in RadioAccessSpecifier.aidl to RadioAccessSpecifier
+     * @param specifier RadioAccessSpecifier defined in RadioAccessSpecifier.aidl
+     * @return The converted RadioAccessSpecifier
+     */
+    public static RadioAccessSpecifier convertHalRadioAccessSpecifier(
+            android.hardware.radio.network.RadioAccessSpecifier specifier) {
+        if (specifier == null) return null;
+        int[] halBands = null;
+        switch (specifier.bands.getTag()) {
+            case android.hardware.radio.network.RadioAccessSpecifierBands.geranBands:
+                halBands = specifier.bands.getGeranBands();
+                break;
+            case android.hardware.radio.network.RadioAccessSpecifierBands.utranBands:
+                halBands = specifier.bands.getUtranBands();
+                break;
+            case android.hardware.radio.network.RadioAccessSpecifierBands.eutranBands:
+                halBands = specifier.bands.getEutranBands();
+                break;
+            case android.hardware.radio.network.RadioAccessSpecifierBands.ngranBands:
+                halBands = specifier.bands.getNgranBands();
+                break;
+        }
+        return new RadioAccessSpecifier(specifier.accessNetwork, halBands, specifier.channels);
+    }
+
+    /**
      * Convert to RadioAccessSpecifier defined in radio/1.1/types.hal
      * @param ras Radio access specifier
      * @return The converted RadioAccessSpecifier
@@ -1094,7 +1359,6 @@
      * @param hwListRil List of HardwareConfig defined in radio/1.0/types.hal
      * @return The converted list of HardwareConfig
      */
-    @TelephonyManager.NetworkTypeBitMask
     public static ArrayList<HardwareConfig> convertHalHardwareConfigList(
             ArrayList<android.hardware.radio.V1_0.HardwareConfig> hwListRil) {
         int num;
@@ -1130,6 +1394,41 @@
     }
 
     /**
+     * Convert a list of HardwareConfig defined in HardwareConfig.aidl to a list of HardwareConfig
+     * @param hwListRil List of HardwareConfig defined in HardwareConfig.aidl
+     * @return The converted list of HardwareConfig
+     */
+    public static ArrayList<HardwareConfig> convertHalHardwareConfigList(
+            android.hardware.radio.modem.HardwareConfig[] hwListRil) {
+        ArrayList<HardwareConfig> response = new ArrayList<>(hwListRil.length);
+        HardwareConfig hw;
+
+        for (android.hardware.radio.modem.HardwareConfig hwRil : hwListRil) {
+            int type = hwRil.type;
+            switch (type) {
+                case HardwareConfig.DEV_HARDWARE_TYPE_MODEM: {
+                    hw = new HardwareConfig(type);
+                    android.hardware.radio.modem.HardwareConfigModem hwModem = hwRil.modem[0];
+                    hw.assignModem(hwRil.uuid, hwRil.state, hwModem.rilModel, hwModem.rat,
+                            hwModem.maxVoiceCalls, hwModem.maxDataCalls, hwModem.maxStandby);
+                    break;
+                }
+                case HardwareConfig.DEV_HARDWARE_TYPE_SIM: {
+                    hw = new HardwareConfig(type);
+                    hw.assignSim(hwRil.uuid, hwRil.state, hwRil.sim[0].modemUuid);
+                    break;
+                }
+                default: {
+                    throw new RuntimeException(
+                            "RIL_REQUEST_GET_HARDWARE_CONFIG invalid hardware type:" + type);
+                }
+            }
+            response.add(hw);
+        }
+        return response;
+    }
+
+    /**
      * Convert RadioCapability defined in radio/1.0/types.hal to RadioCapability
      * @param rc RadioCapability defined in radio/1.0/types.hal
      * @param ril RIL
@@ -1150,12 +1449,75 @@
     }
 
     /**
-     * Convert LceDataInfo defined in radio/1.0/types.hal to a list of LinkCapacityEstimates
-     * @param lce LceDataInfo defined in radio/1.0/types.hal
+     * Convert RadioCapability defined in RadioCapability.aidl to RadioCapability
+     * @param rc RadioCapability defined in RadioCapability.aidl
+     * @param ril RIL
+     * @return The converted RadioCapability
+     */
+    public static RadioCapability convertHalRadioCapability(
+            android.hardware.radio.modem.RadioCapability rc, RIL ril) {
+        int session = rc.session;
+        int phase = rc.phase;
+        int rat = convertHalNetworkTypeBitMask(rc.raf);
+        String logicModemUuid = rc.logicalModemUuid;
+        int status = rc.status;
+
+        ril.riljLog("convertHalRadioCapability: session=" + session + ", phase=" + phase + ", rat="
+                + rat + ", logicModemUuid=" + logicModemUuid + ", status=" + status + ", rcRil.raf="
+                + rc.raf);
+        return new RadioCapability(ril.mPhoneId, session, phase, rat, logicModemUuid, status);
+    }
+
+    /**
+     * Convert LceDataInfo defined in radio/1.0/types.hal and LinkCapacityEstimate defined in
+     * radio/1.2, 1.6/types.hal to a list of LinkCapacityEstimates
+     * @param lceObj LceDataInfo defined in radio/1.0/types.hal or LinkCapacityEstimate defined in
+     *        radio/1.2, 1.6/types.hal
+     * @return The converted list of LinkCapacityEstimates
+     */
+    public static List<LinkCapacityEstimate> convertHalLceData(Object lceObj) {
+        final List<LinkCapacityEstimate> lceList = new ArrayList<>();
+        if (lceObj == null) return lceList;
+        if (lceObj instanceof android.hardware.radio.V1_0.LceDataInfo) {
+            android.hardware.radio.V1_0.LceDataInfo lce =
+                    (android.hardware.radio.V1_0.LceDataInfo) lceObj;
+            lceList.add(new LinkCapacityEstimate(LinkCapacityEstimate.LCE_TYPE_COMBINED,
+                    lce.lastHopCapacityKbps, LinkCapacityEstimate.INVALID));
+        } else if (lceObj instanceof android.hardware.radio.V1_2.LinkCapacityEstimate) {
+            android.hardware.radio.V1_2.LinkCapacityEstimate lce =
+                    (android.hardware.radio.V1_2.LinkCapacityEstimate) lceObj;
+            lceList.add(new LinkCapacityEstimate(LinkCapacityEstimate.LCE_TYPE_COMBINED,
+                    lce.downlinkCapacityKbps, lce.uplinkCapacityKbps));
+        } else if (lceObj instanceof android.hardware.radio.V1_6.LinkCapacityEstimate) {
+            android.hardware.radio.V1_6.LinkCapacityEstimate lce =
+                    (android.hardware.radio.V1_6.LinkCapacityEstimate) lceObj;
+            int primaryDownlinkCapacityKbps = lce.downlinkCapacityKbps;
+            int primaryUplinkCapacityKbps = lce.uplinkCapacityKbps;
+            if (primaryDownlinkCapacityKbps != LinkCapacityEstimate.INVALID
+                    && lce.secondaryDownlinkCapacityKbps != LinkCapacityEstimate.INVALID) {
+                primaryDownlinkCapacityKbps =
+                        lce.downlinkCapacityKbps - lce.secondaryDownlinkCapacityKbps;
+            }
+            if (primaryUplinkCapacityKbps != LinkCapacityEstimate.INVALID
+                    && lce.secondaryUplinkCapacityKbps != LinkCapacityEstimate.INVALID) {
+                primaryUplinkCapacityKbps =
+                        lce.uplinkCapacityKbps - lce.secondaryUplinkCapacityKbps;
+            }
+            lceList.add(new LinkCapacityEstimate(LinkCapacityEstimate.LCE_TYPE_PRIMARY,
+                    primaryDownlinkCapacityKbps, primaryUplinkCapacityKbps));
+            lceList.add(new LinkCapacityEstimate(LinkCapacityEstimate.LCE_TYPE_SECONDARY,
+                    lce.secondaryDownlinkCapacityKbps, lce.secondaryUplinkCapacityKbps));
+        }
+        return lceList;
+    }
+
+    /**
+     * Convert LceDataInfo defined in LceDataInfo.aidl to a list of LinkCapacityEstimates
+     * @param lce LceDataInfo defined in LceDataInfo.aidl
      * @return The converted list of LinkCapacityEstimates
      */
     public static List<LinkCapacityEstimate> convertHalLceData(
-            android.hardware.radio.V1_0.LceDataInfo lce) {
+            android.hardware.radio.network.LceDataInfo lce) {
         final List<LinkCapacityEstimate> lceList = new ArrayList<>();
         lceList.add(new LinkCapacityEstimate(LinkCapacityEstimate.LCE_TYPE_COMBINED,
                 lce.lastHopCapacityKbps, LinkCapacityEstimate.INVALID));
@@ -1163,27 +1525,13 @@
     }
 
     /**
-     * Convert LinkCapacityEstimate defined in radio/1.2/types.hal to a list of
+     * Convert LinkCapacityEstimate defined in LinkCapacityEstimate.aidl to a list of
      * LinkCapacityEstimates
-     * @param lce LinkCapacityEstimate defined in radio/1.2/types.hal
+     * @param lce LinkCapacityEstimate defined in LinkCapacityEstimate.aidl
      * @return The converted list of LinkCapacityEstimates
      */
     public static List<LinkCapacityEstimate> convertHalLceData(
-            android.hardware.radio.V1_2.LinkCapacityEstimate lce) {
-        final List<LinkCapacityEstimate> lceList = new ArrayList<>();
-        lceList.add(new LinkCapacityEstimate(LinkCapacityEstimate.LCE_TYPE_COMBINED,
-                lce.downlinkCapacityKbps, lce.uplinkCapacityKbps));
-        return lceList;
-    }
-
-    /**
-     * Convert LinkCapacityEstimate defined in radio/1.6/types.hal to a list of
-     * LinkCapacityEstimates
-     * @param lce LinkCapacityEstimate defined in radio/1.6/types.hal
-     * @return The converted list of LinkCapacityEstimates
-     */
-    public static List<LinkCapacityEstimate> convertHalLceData(
-            android.hardware.radio.V1_6.LinkCapacityEstimate lce) {
+            android.hardware.radio.network.LinkCapacityEstimate lce) {
         final List<LinkCapacityEstimate> lceList = new ArrayList<>();
         int primaryDownlinkCapacityKbps = lce.downlinkCapacityKbps;
         int primaryUplinkCapacityKbps = lce.uplinkCapacityKbps;
@@ -1204,6 +1552,7 @@
         return lceList;
     }
 
+
     /**
      * Convert a list of CellInfo defined in radio/1.0, 1.2, 1.4, 1.5, 1.6/types.hal to a list of
      * CellInfos
@@ -1220,33 +1569,1109 @@
         return response;
     }
 
+    /**
+     * Convert a list of CellInfo defined in CellInfo.aidl to a list of CellInfos
+     * @param records List of CellInfo defined in CellInfo.aidl
+     * @return The converted list of CellInfos
+     */
+    public static ArrayList<CellInfo> convertHalCellInfoList(
+            android.hardware.radio.network.CellInfo[] records) {
+        ArrayList<CellInfo> response = new ArrayList<>(records.length);
+        if (records.length == 0) return response;
+        final long nanotime = SystemClock.elapsedRealtimeNanos();
+        for (android.hardware.radio.network.CellInfo ci : records) {
+            response.add(convertHalCellInfo(ci, nanotime));
+        }
+        return response;
+    }
+
+    /**
+     * Convert a CellInfo defined in radio/1.0, 1.2, 1.4, 1.5, 1.6/types.hal to CellInfo
+     * @param cellInfo CellInfo defined in radio/1.0, 1.2, 1.4, 1.5, 1.6/types.hal
+     * @param nanotime time the CellInfo was created
+     * @return The converted CellInfo
+     */
     private static CellInfo convertHalCellInfo(Object cellInfo, long nanotime) {
         if (cellInfo == null) return null;
+        int type;
+        int connectionStatus;
+        boolean registered;
+        CellIdentityGsm gsmCi = null;
+        CellSignalStrengthGsm gsmSs = null;
+        CellIdentityCdma cdmaCi = null;
+        CellSignalStrengthCdma cdmaSs = null;
+        CellIdentityLte lteCi = null;
+        CellSignalStrengthLte lteSs = null;
+        CellConfigLte lteCc = null;
+        CellIdentityWcdma wcdmaCi = null;
+        CellSignalStrengthWcdma wcdmaSs = null;
+        CellIdentityTdscdma tdscdmaCi = null;
+        CellSignalStrengthTdscdma tdscdmaSs = null;
+        CellIdentityNr nrCi = null;
+        CellSignalStrengthNr nrSs = null;
         if (cellInfo instanceof android.hardware.radio.V1_0.CellInfo) {
             final android.hardware.radio.V1_0.CellInfo record =
                     (android.hardware.radio.V1_0.CellInfo) cellInfo;
-            record.timeStamp = nanotime;
-            return CellInfo.create(record);
+            connectionStatus = CellInfo.CONNECTION_UNKNOWN;
+            registered = record.registered;
+            switch (record.cellInfoType) {
+                case android.hardware.radio.V1_0.CellInfoType.GSM:
+                    type = CellInfo.TYPE_GSM;
+                    android.hardware.radio.V1_0.CellInfoGsm gsm = record.gsm.get(0);
+                    gsmCi = convertHalCellIdentityGsm(gsm.cellIdentityGsm);
+                    gsmSs = convertHalGsmSignalStrength(gsm.signalStrengthGsm);
+                    break;
+                case android.hardware.radio.V1_0.CellInfoType.CDMA:
+                    type = CellInfo.TYPE_CDMA;
+                    android.hardware.radio.V1_0.CellInfoCdma cdma = record.cdma.get(0);
+                    cdmaCi = convertHalCellIdentityCdma(cdma.cellIdentityCdma);
+                    cdmaSs = convertHalCdmaSignalStrength(
+                            cdma.signalStrengthCdma, cdma.signalStrengthEvdo);
+                    break;
+                case android.hardware.radio.V1_0.CellInfoType.LTE:
+                    type = CellInfo.TYPE_LTE;
+                    android.hardware.radio.V1_0.CellInfoLte lte = record.lte.get(0);
+                    lteCi = convertHalCellIdentityLte(lte.cellIdentityLte);
+                    lteSs = convertHalLteSignalStrength(lte.signalStrengthLte);
+                    lteCc = new CellConfigLte();
+                    break;
+                case android.hardware.radio.V1_0.CellInfoType.WCDMA:
+                    type = CellInfo.TYPE_WCDMA;
+                    android.hardware.radio.V1_0.CellInfoWcdma wcdma = record.wcdma.get(0);
+                    wcdmaCi = convertHalCellIdentityWcdma(wcdma.cellIdentityWcdma);
+                    wcdmaSs = convertHalWcdmaSignalStrength(wcdma.signalStrengthWcdma);
+                    break;
+                case android.hardware.radio.V1_0.CellInfoType.TD_SCDMA:
+                    type = CellInfo.TYPE_TDSCDMA;
+                    android.hardware.radio.V1_0.CellInfoTdscdma tdscdma = record.tdscdma.get(0);
+                    tdscdmaCi = convertHalCellIdentityTdscdma(tdscdma.cellIdentityTdscdma);
+                    tdscdmaSs = convertHalTdscdmaSignalStrength(tdscdma.signalStrengthTdscdma);
+                    break;
+                default: return null;
+            }
         } else if (cellInfo instanceof android.hardware.radio.V1_2.CellInfo) {
             final android.hardware.radio.V1_2.CellInfo record =
                     (android.hardware.radio.V1_2.CellInfo) cellInfo;
-            record.timeStamp = nanotime;
-            return CellInfo.create(record);
+            connectionStatus = record.connectionStatus;
+            registered = record.registered;
+            switch(record.cellInfoType) {
+                case android.hardware.radio.V1_0.CellInfoType.GSM:
+                    type = CellInfo.TYPE_GSM;
+                    android.hardware.radio.V1_2.CellInfoGsm gsm = record.gsm.get(0);
+                    gsmCi = convertHalCellIdentityGsm(gsm.cellIdentityGsm);
+                    gsmSs = convertHalGsmSignalStrength(gsm.signalStrengthGsm);
+                    break;
+                case android.hardware.radio.V1_0.CellInfoType.CDMA:
+                    type = CellInfo.TYPE_CDMA;
+                    android.hardware.radio.V1_2.CellInfoCdma cdma = record.cdma.get(0);
+                    cdmaCi = convertHalCellIdentityCdma(cdma.cellIdentityCdma);
+                    cdmaSs = convertHalCdmaSignalStrength(
+                            cdma.signalStrengthCdma, cdma.signalStrengthEvdo);
+                    break;
+                case android.hardware.radio.V1_0.CellInfoType.LTE:
+                    type = CellInfo.TYPE_LTE;
+                    android.hardware.radio.V1_2.CellInfoLte lte = record.lte.get(0);
+                    lteCi = convertHalCellIdentityLte(lte.cellIdentityLte);
+                    lteSs = convertHalLteSignalStrength(lte.signalStrengthLte);
+                    lteCc = new CellConfigLte();
+                    break;
+                case android.hardware.radio.V1_0.CellInfoType.WCDMA:
+                    type = CellInfo.TYPE_WCDMA;
+                    android.hardware.radio.V1_2.CellInfoWcdma wcdma = record.wcdma.get(0);
+                    wcdmaCi = convertHalCellIdentityWcdma(wcdma.cellIdentityWcdma);
+                    wcdmaSs = convertHalWcdmaSignalStrength(wcdma.signalStrengthWcdma);
+                    break;
+                case android.hardware.radio.V1_0.CellInfoType.TD_SCDMA:
+                    type = CellInfo.TYPE_TDSCDMA;
+                    android.hardware.radio.V1_2.CellInfoTdscdma tdscdma = record.tdscdma.get(0);
+                    tdscdmaCi = convertHalCellIdentityTdscdma(tdscdma.cellIdentityTdscdma);
+                    tdscdmaSs = convertHalTdscdmaSignalStrength(tdscdma.signalStrengthTdscdma);
+                    break;
+                default: return null;
+            }
         } else if (cellInfo instanceof android.hardware.radio.V1_4.CellInfo) {
             final android.hardware.radio.V1_4.CellInfo record =
                     (android.hardware.radio.V1_4.CellInfo) cellInfo;
-            return CellInfo.create(record, nanotime);
+            connectionStatus = record.connectionStatus;
+            registered = record.isRegistered;
+            switch (record.info.getDiscriminator()) {
+                case android.hardware.radio.V1_4.CellInfo.Info.hidl_discriminator.gsm:
+                    type = CellInfo.TYPE_GSM;
+                    android.hardware.radio.V1_2.CellInfoGsm gsm = record.info.gsm();
+                    gsmCi = convertHalCellIdentityGsm(gsm.cellIdentityGsm);
+                    gsmSs = convertHalGsmSignalStrength(gsm.signalStrengthGsm);
+                    break;
+                case android.hardware.radio.V1_4.CellInfo.Info.hidl_discriminator.cdma:
+                    type = CellInfo.TYPE_CDMA;
+                    android.hardware.radio.V1_2.CellInfoCdma cdma = record.info.cdma();
+                    cdmaCi = convertHalCellIdentityCdma(cdma.cellIdentityCdma);
+                    cdmaSs = convertHalCdmaSignalStrength(
+                            cdma.signalStrengthCdma, cdma.signalStrengthEvdo);
+                    break;
+                case android.hardware.radio.V1_4.CellInfo.Info.hidl_discriminator.lte:
+                    type = CellInfo.TYPE_LTE;
+                    android.hardware.radio.V1_4.CellInfoLte lte = record.info.lte();
+                    lteCi = convertHalCellIdentityLte(lte.base.cellIdentityLte);
+                    lteSs = convertHalLteSignalStrength(lte.base.signalStrengthLte);
+                    lteCc = new CellConfigLte(lte.cellConfig.isEndcAvailable);
+                    break;
+                case android.hardware.radio.V1_4.CellInfo.Info.hidl_discriminator.wcdma:
+                    type = CellInfo.TYPE_WCDMA;
+                    android.hardware.radio.V1_2.CellInfoWcdma wcdma = record.info.wcdma();
+                    wcdmaCi = convertHalCellIdentityWcdma(wcdma.cellIdentityWcdma);
+                    wcdmaSs = convertHalWcdmaSignalStrength(wcdma.signalStrengthWcdma);
+                    break;
+                case android.hardware.radio.V1_4.CellInfo.Info.hidl_discriminator.tdscdma:
+                    type = CellInfo.TYPE_TDSCDMA;
+                    android.hardware.radio.V1_2.CellInfoTdscdma tdscdma = record.info.tdscdma();
+                    tdscdmaCi = convertHalCellIdentityTdscdma(tdscdma.cellIdentityTdscdma);
+                    tdscdmaSs = convertHalTdscdmaSignalStrength(tdscdma.signalStrengthTdscdma);
+                    break;
+                case android.hardware.radio.V1_4.CellInfo.Info.hidl_discriminator.nr:
+                    type = CellInfo.TYPE_NR;
+                    android.hardware.radio.V1_4.CellInfoNr nr = record.info.nr();
+                    nrCi = convertHalCellIdentityNr(nr.cellidentity);
+                    nrSs = convertHalNrSignalStrength(nr.signalStrength);
+                    break;
+                default: return null;
+            }
         } else if (cellInfo instanceof android.hardware.radio.V1_5.CellInfo) {
             final android.hardware.radio.V1_5.CellInfo record =
                     (android.hardware.radio.V1_5.CellInfo) cellInfo;
-            return CellInfo.create(record, nanotime);
+            connectionStatus = record.connectionStatus;
+            registered = record.registered;
+            switch (record.ratSpecificInfo.getDiscriminator()) {
+                case android.hardware.radio.V1_5.CellInfo
+                        .CellInfoRatSpecificInfo.hidl_discriminator.gsm:
+                    type = CellInfo.TYPE_GSM;
+                    android.hardware.radio.V1_5.CellInfoGsm gsm = record.ratSpecificInfo.gsm();
+                    gsmCi = convertHalCellIdentityGsm(gsm.cellIdentityGsm);
+                    gsmSs = convertHalGsmSignalStrength(gsm.signalStrengthGsm);
+                    break;
+                case android.hardware.radio.V1_5.CellInfo
+                        .CellInfoRatSpecificInfo.hidl_discriminator.cdma:
+                    type = CellInfo.TYPE_CDMA;
+                    android.hardware.radio.V1_2.CellInfoCdma cdma = record.ratSpecificInfo.cdma();
+                    cdmaCi = convertHalCellIdentityCdma(cdma.cellIdentityCdma);
+                    cdmaSs = convertHalCdmaSignalStrength(
+                            cdma.signalStrengthCdma, cdma.signalStrengthEvdo);
+                    break;
+                case android.hardware.radio.V1_5.CellInfo
+                        .CellInfoRatSpecificInfo.hidl_discriminator.lte:
+                    type = CellInfo.TYPE_LTE;
+                    android.hardware.radio.V1_5.CellInfoLte lte = record.ratSpecificInfo.lte();
+                    lteCi = convertHalCellIdentityLte(lte.cellIdentityLte);
+                    lteSs = convertHalLteSignalStrength(lte.signalStrengthLte);
+                    lteCc = new CellConfigLte();
+                    break;
+                case android.hardware.radio.V1_5.CellInfo
+                        .CellInfoRatSpecificInfo.hidl_discriminator.wcdma:
+                    type = CellInfo.TYPE_WCDMA;
+                    android.hardware.radio.V1_5.CellInfoWcdma wcdma =
+                            record.ratSpecificInfo.wcdma();
+                    wcdmaCi = convertHalCellIdentityWcdma(wcdma.cellIdentityWcdma);
+                    wcdmaSs = convertHalWcdmaSignalStrength(wcdma.signalStrengthWcdma);
+                    break;
+                case android.hardware.radio.V1_5.CellInfo
+                        .CellInfoRatSpecificInfo.hidl_discriminator.tdscdma:
+                    type = CellInfo.TYPE_TDSCDMA;
+                    android.hardware.radio.V1_5.CellInfoTdscdma tdscdma =
+                            record.ratSpecificInfo.tdscdma();
+                    tdscdmaCi = convertHalCellIdentityTdscdma(tdscdma.cellIdentityTdscdma);
+                    tdscdmaSs = convertHalTdscdmaSignalStrength(tdscdma.signalStrengthTdscdma);
+                    break;
+                case android.hardware.radio.V1_5.CellInfo
+                        .CellInfoRatSpecificInfo.hidl_discriminator.nr:
+                    type = CellInfo.TYPE_NR;
+                    android.hardware.radio.V1_5.CellInfoNr nr = record.ratSpecificInfo.nr();
+                    nrCi = convertHalCellIdentityNr(nr.cellIdentityNr);
+                    nrSs = convertHalNrSignalStrength(nr.signalStrengthNr);
+                    break;
+                default: return null;
+            }
         } else if (cellInfo instanceof android.hardware.radio.V1_6.CellInfo) {
             final android.hardware.radio.V1_6.CellInfo record =
                     (android.hardware.radio.V1_6.CellInfo) cellInfo;
-            return CellInfo.create(record, nanotime);
+            connectionStatus = record.connectionStatus;
+            registered = record.registered;
+            switch (record.ratSpecificInfo.getDiscriminator()) {
+                case android.hardware.radio.V1_6.CellInfo
+                        .CellInfoRatSpecificInfo.hidl_discriminator.gsm:
+                    type = CellInfo.TYPE_GSM;
+                    android.hardware.radio.V1_5.CellInfoGsm gsm = record.ratSpecificInfo.gsm();
+                    gsmCi = convertHalCellIdentityGsm(gsm.cellIdentityGsm);
+                    gsmSs = convertHalGsmSignalStrength(gsm.signalStrengthGsm);
+                    break;
+                case android.hardware.radio.V1_6.CellInfo
+                        .CellInfoRatSpecificInfo.hidl_discriminator.cdma:
+                    type = CellInfo.TYPE_CDMA;
+                    android.hardware.radio.V1_2.CellInfoCdma cdma = record.ratSpecificInfo.cdma();
+                    cdmaCi = convertHalCellIdentityCdma(cdma.cellIdentityCdma);
+                    cdmaSs = convertHalCdmaSignalStrength(
+                            cdma.signalStrengthCdma, cdma.signalStrengthEvdo);
+                    break;
+                case android.hardware.radio.V1_6.CellInfo
+                        .CellInfoRatSpecificInfo.hidl_discriminator.lte:
+                    type = CellInfo.TYPE_LTE;
+                    android.hardware.radio.V1_6.CellInfoLte lte = record.ratSpecificInfo.lte();
+                    lteCi = convertHalCellIdentityLte(lte.cellIdentityLte);
+                    lteSs = convertHalLteSignalStrength(lte.signalStrengthLte);
+                    lteCc = new CellConfigLte();
+                    break;
+                case android.hardware.radio.V1_6.CellInfo
+                        .CellInfoRatSpecificInfo.hidl_discriminator.wcdma:
+                    type = CellInfo.TYPE_WCDMA;
+                    android.hardware.radio.V1_5.CellInfoWcdma wcdma =
+                            record.ratSpecificInfo.wcdma();
+                    wcdmaCi = convertHalCellIdentityWcdma(wcdma.cellIdentityWcdma);
+                    wcdmaSs = convertHalWcdmaSignalStrength(wcdma.signalStrengthWcdma);
+                    break;
+                case android.hardware.radio.V1_6.CellInfo
+                        .CellInfoRatSpecificInfo.hidl_discriminator.tdscdma:
+                    type = CellInfo.TYPE_TDSCDMA;
+                    android.hardware.radio.V1_5.CellInfoTdscdma tdscdma =
+                            record.ratSpecificInfo.tdscdma();
+                    tdscdmaCi = convertHalCellIdentityTdscdma(tdscdma.cellIdentityTdscdma);
+                    tdscdmaSs = convertHalTdscdmaSignalStrength(tdscdma.signalStrengthTdscdma);
+                    break;
+                case android.hardware.radio.V1_6.CellInfo
+                        .CellInfoRatSpecificInfo.hidl_discriminator.nr:
+                    type = CellInfo.TYPE_NR;
+                    android.hardware.radio.V1_6.CellInfoNr nr = record.ratSpecificInfo.nr();
+                    nrCi = convertHalCellIdentityNr(nr.cellIdentityNr);
+                    nrSs = convertHalNrSignalStrength(nr.signalStrengthNr);
+                    break;
+                default: return null;
+            }
         } else {
             return null;
         }
+
+        switch (type) {
+            case CellInfo.TYPE_GSM:
+                return new CellInfoGsm(connectionStatus, registered, nanotime, gsmCi, gsmSs);
+            case CellInfo.TYPE_CDMA:
+                return new CellInfoCdma(connectionStatus, registered, nanotime, cdmaCi, cdmaSs);
+            case CellInfo.TYPE_LTE:
+                return new CellInfoLte(connectionStatus, registered, nanotime, lteCi, lteSs, lteCc);
+            case CellInfo.TYPE_WCDMA:
+                return new CellInfoWcdma(connectionStatus, registered, nanotime, wcdmaCi, wcdmaSs);
+            case CellInfo.TYPE_TDSCDMA:
+                return new CellInfoTdscdma(connectionStatus, registered, nanotime, tdscdmaCi,
+                        tdscdmaSs);
+            case CellInfo.TYPE_NR:
+                return new CellInfoNr(connectionStatus, registered, nanotime, nrCi, nrSs);
+            case CellInfo.TYPE_UNKNOWN:
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * Convert a CellInfo defined in radio/1.0, 1.2, 1.4, 1.5, 1.6/types.hal to CellInfo
+     * @param cellInfo CellInfo defined in radio/1.0, 1.2, 1.4, 1.5, 1.6/types.hal
+     * @param nanotime time the CellInfo was created
+     * @return The converted CellInfo
+     */
+    private static CellInfo convertHalCellInfo(android.hardware.radio.network.CellInfo cellInfo,
+            long nanotime) {
+        if (cellInfo == null) return null;
+        int connectionStatus = cellInfo.connectionStatus;
+        boolean registered = cellInfo.registered;
+        switch (cellInfo.ratSpecificInfo.getTag()) {
+            case android.hardware.radio.network.CellInfoRatSpecificInfo.gsm:
+                android.hardware.radio.network.CellInfoGsm gsm = cellInfo.ratSpecificInfo.getGsm();
+                return new CellInfoGsm(connectionStatus, registered, nanotime,
+                        convertHalCellIdentityGsm(gsm.cellIdentityGsm),
+                        convertHalGsmSignalStrength(gsm.signalStrengthGsm));
+            case android.hardware.radio.network.CellInfoRatSpecificInfo.cdma:
+                android.hardware.radio.network.CellInfoCdma cdma =
+                        cellInfo.ratSpecificInfo.getCdma();
+                return new CellInfoCdma(connectionStatus, registered, nanotime,
+                        convertHalCellIdentityCdma(cdma.cellIdentityCdma),
+                        convertHalCdmaSignalStrength(cdma.signalStrengthCdma,
+                                cdma.signalStrengthEvdo));
+            case android.hardware.radio.network.CellInfoRatSpecificInfo.lte:
+                android.hardware.radio.network.CellInfoLte lte = cellInfo.ratSpecificInfo.getLte();
+                return new CellInfoLte(connectionStatus, registered, nanotime,
+                        convertHalCellIdentityLte(lte.cellIdentityLte),
+                        convertHalLteSignalStrength(lte.signalStrengthLte), new CellConfigLte());
+            case android.hardware.radio.network.CellInfoRatSpecificInfo.wcdma:
+                android.hardware.radio.network.CellInfoWcdma wcdma =
+                        cellInfo.ratSpecificInfo.getWcdma();
+                return new CellInfoWcdma(connectionStatus, registered, nanotime,
+                        convertHalCellIdentityWcdma(wcdma.cellIdentityWcdma),
+                        convertHalWcdmaSignalStrength(wcdma.signalStrengthWcdma));
+            case android.hardware.radio.network.CellInfoRatSpecificInfo.tdscdma:
+                android.hardware.radio.network.CellInfoTdscdma tdscdma =
+                        cellInfo.ratSpecificInfo.getTdscdma();
+                return new CellInfoTdscdma(connectionStatus, registered, nanotime,
+                        convertHalCellIdentityTdscdma(tdscdma.cellIdentityTdscdma),
+                        convertHalTdscdmaSignalStrength(tdscdma.signalStrengthTdscdma));
+            case android.hardware.radio.network.CellInfoRatSpecificInfo.nr:
+                android.hardware.radio.network.CellInfoNr nr = cellInfo.ratSpecificInfo.getNr();
+                return new CellInfoNr(connectionStatus, registered, nanotime,
+                        convertHalCellIdentityNr(nr.cellIdentityNr),
+                        convertHalNrSignalStrength(nr.signalStrengthNr));
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * Convert a CellIdentity defined in radio/1.0, 1.2, 1.5/types.hal to CellIdentity
+     * @param halCi CellIdentity defined in radio/1.0, 1.2, 1.5/types.hal
+     * @return The converted CellIdentity
+     */
+    public static CellIdentity convertHalCellIdentity(Object halCi) {
+        if (halCi == null) return null;
+        if (halCi instanceof android.hardware.radio.V1_0.CellIdentity) {
+            android.hardware.radio.V1_0.CellIdentity ci =
+                    (android.hardware.radio.V1_0.CellIdentity) halCi;
+            switch (ci.cellInfoType) {
+                case CellInfo.TYPE_GSM:
+                    if (ci.cellIdentityGsm.size() == 1) {
+                        return convertHalCellIdentityGsm(ci.cellIdentityGsm.get(0));
+                    }
+                    break;
+                case CellInfo.TYPE_CDMA:
+                    if (ci.cellIdentityCdma.size() == 1) {
+                        return convertHalCellIdentityCdma(ci.cellIdentityCdma.get(0));
+                    }
+                    break;
+                case CellInfo.TYPE_LTE:
+                    if (ci.cellIdentityLte.size() == 1) {
+                        return convertHalCellIdentityLte(ci.cellIdentityLte.get(0));
+                    }
+                    break;
+                case CellInfo.TYPE_WCDMA:
+                    if (ci.cellIdentityWcdma.size() == 1) {
+                        return convertHalCellIdentityWcdma(ci.cellIdentityWcdma.get(0));
+                    }
+                    break;
+                case CellInfo.TYPE_TDSCDMA:
+                    if (ci.cellIdentityTdscdma.size() == 1) {
+                        return convertHalCellIdentityTdscdma(ci.cellIdentityTdscdma.get(0));
+                    }
+                    break;
+            }
+        } else if (halCi instanceof android.hardware.radio.V1_2.CellIdentity) {
+            android.hardware.radio.V1_2.CellIdentity ci =
+                    (android.hardware.radio.V1_2.CellIdentity) halCi;
+            switch (ci.cellInfoType) {
+                case CellInfo.TYPE_GSM:
+                    if (ci.cellIdentityGsm.size() == 1) {
+                        return convertHalCellIdentityGsm(ci.cellIdentityGsm.get(0));
+                    }
+                    break;
+                case CellInfo.TYPE_CDMA:
+                    if (ci.cellIdentityCdma.size() == 1) {
+                        return convertHalCellIdentityCdma(ci.cellIdentityCdma.get(0));
+                    }
+                    break;
+                case CellInfo.TYPE_LTE:
+                    if (ci.cellIdentityLte.size() == 1) {
+                        return convertHalCellIdentityLte(ci.cellIdentityLte.get(0));
+                    }
+                    break;
+                case CellInfo.TYPE_WCDMA:
+                    if (ci.cellIdentityWcdma.size() == 1) {
+                        return convertHalCellIdentityWcdma(ci.cellIdentityWcdma.get(0));
+                    }
+                    break;
+                case CellInfo.TYPE_TDSCDMA:
+                    if (ci.cellIdentityTdscdma.size() == 1) {
+                        return convertHalCellIdentityTdscdma(ci.cellIdentityTdscdma.get(0));
+                    }
+                    break;
+            }
+        } else if (halCi instanceof android.hardware.radio.V1_5.CellIdentity) {
+            android.hardware.radio.V1_5.CellIdentity ci =
+                    (android.hardware.radio.V1_5.CellIdentity) halCi;
+            switch (ci.getDiscriminator()) {
+                case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.gsm:
+                    return convertHalCellIdentityGsm(ci.gsm());
+                case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.cdma:
+                    return convertHalCellIdentityCdma(ci.cdma());
+                case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.lte:
+                    return convertHalCellIdentityLte(ci.lte());
+                case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.wcdma:
+                    return convertHalCellIdentityWcdma(ci.wcdma());
+                case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.tdscdma:
+                    return convertHalCellIdentityTdscdma(ci.tdscdma());
+                case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.nr:
+                    return convertHalCellIdentityNr(ci.nr());
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Convert a CellIdentity defined in CellIdentity.aidl to CellInfo
+     * @param ci CellIdentity defined in CellIdentity.aidl
+     * @return The converted CellIdentity
+     */
+    public static CellIdentity convertHalCellIdentity(
+            android.hardware.radio.network.CellIdentity ci) {
+        if (ci == null) return null;
+        switch (ci.getTag()) {
+            case android.hardware.radio.network.CellIdentity.gsm:
+                return convertHalCellIdentityGsm(ci.getGsm());
+            case android.hardware.radio.network.CellIdentity.cdma:
+                return convertHalCellIdentityCdma(ci.getCdma());
+            case android.hardware.radio.network.CellIdentity.lte:
+                return convertHalCellIdentityLte(ci.getLte());
+            case android.hardware.radio.network.CellIdentity.wcdma:
+                return convertHalCellIdentityWcdma(ci.getWcdma());
+            case android.hardware.radio.network.CellIdentity.tdscdma:
+                return convertHalCellIdentityTdscdma(ci.getTdscdma());
+            case android.hardware.radio.network.CellIdentity.nr:
+                return convertHalCellIdentityNr(ci.getNr());
+            default: return null;
+        }
+    }
+
+    /**
+     * Convert a CellIdentityGsm defined in radio/1.0, 1.2, 1.5/types.hal to CellIdentityGsm
+     * @param gsm CellIdentityGsm defined in radio/1.0, 1.2, 1.5/types.hal
+     * @return The converted CellIdentityGsm
+     */
+    public static CellIdentityGsm convertHalCellIdentityGsm(Object gsm) {
+        if (gsm == null) return null;
+        if (gsm instanceof android.hardware.radio.V1_0.CellIdentityGsm) {
+            android.hardware.radio.V1_0.CellIdentityGsm ci =
+                    (android.hardware.radio.V1_0.CellIdentityGsm) gsm;
+            return new CellIdentityGsm(ci.lac, ci.cid, ci.arfcn,
+                    ci.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE : ci.bsic, ci.mcc, ci.mnc, "", "",
+                    new ArraySet<>());
+        } else if (gsm instanceof android.hardware.radio.V1_2.CellIdentityGsm) {
+            android.hardware.radio.V1_2.CellIdentityGsm ci =
+                    (android.hardware.radio.V1_2.CellIdentityGsm) gsm;
+            return new CellIdentityGsm(ci.base.lac, ci.base.cid, ci.base.arfcn,
+                    ci.base.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE : ci.base.bsic, ci.base.mcc,
+                    ci.base.mnc, ci.operatorNames.alphaLong, ci.operatorNames.alphaShort,
+                    new ArraySet<>());
+        } else if (gsm instanceof android.hardware.radio.V1_5.CellIdentityGsm) {
+            android.hardware.radio.V1_5.CellIdentityGsm ci =
+                    (android.hardware.radio.V1_5.CellIdentityGsm) gsm;
+            return new CellIdentityGsm(ci.base.base.lac, ci.base.base.cid, ci.base.base.arfcn,
+                    ci.base.base.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE
+                            : ci.base.base.bsic, ci.base.base.mcc, ci.base.base.mnc,
+                    ci.base.operatorNames.alphaLong, ci.base.operatorNames.alphaShort,
+                    ci.additionalPlmns);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Convert a CellIdentityGsm defined in CellIdentityGsm.aidl to CellIdentityGsm
+     * @param cid CellIdentityGsm defined in CellIdentityGsm.aidl
+     * @return The converted CellIdentityGsm
+     */
+    public static CellIdentityGsm convertHalCellIdentityGsm(
+            android.hardware.radio.network.CellIdentityGsm cid) {
+        return new CellIdentityGsm(cid.lac, cid.cid, cid.arfcn,
+                cid.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE : cid.bsic, cid.mcc, cid.mnc,
+                "", "", new ArraySet<>());
+    }
+
+    /**
+     * Convert a CellIdentityCdma defined in radio/1.0, 1.2/types.hal to CellIdentityCdma
+     * @param cdma CellIdentityCdma defined in radio/1.0, 1.2/types.hal
+     * @return The converted CellIdentityCdma
+     */
+    public static CellIdentityCdma convertHalCellIdentityCdma(Object cdma) {
+        if (cdma == null) return null;
+        if (cdma instanceof android.hardware.radio.V1_0.CellIdentityCdma) {
+            android.hardware.radio.V1_0.CellIdentityCdma ci =
+                    (android.hardware.radio.V1_0.CellIdentityCdma) cdma;
+            return new CellIdentityCdma(ci.networkId, ci.systemId, ci.baseStationId, ci.longitude,
+                    ci.latitude, "", "");
+        } else if (cdma instanceof android.hardware.radio.V1_2.CellIdentityCdma) {
+            android.hardware.radio.V1_2.CellIdentityCdma ci =
+                    (android.hardware.radio.V1_2.CellIdentityCdma) cdma;
+            return new CellIdentityCdma(ci.base.networkId, ci.base.systemId, ci.base.baseStationId,
+                    ci.base.longitude, ci.base.latitude, ci.operatorNames.alphaLong,
+                    ci.operatorNames.alphaShort);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Convert a CellIdentityCdma defined in CellIdentityCdma.aidl to CellIdentityCdma
+     * @param cid CellIdentityCdma defined in CelIdentityCdma.aidl
+     * @return The converted CellIdentityCdma
+     */
+    public static CellIdentityCdma convertHalCellIdentityCdma(
+            android.hardware.radio.network.CellIdentityCdma cid) {
+        return new CellIdentityCdma(cid.networkId, cid.systemId, cid.baseStationId, cid.longitude,
+                cid.latitude, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort);
+    }
+
+    /**
+     * Convert a CellIdentityLte defined in radio/1.0, 1.2, 1.5/types.hal to CellIdentityLte
+     * @param lte CellIdentityLte defined in radio/1.0, 1.2, 1.5/types.hal
+     * @return The converted CellIdentityLte
+     */
+    public static CellIdentityLte convertHalCellIdentityLte(Object lte) {
+        if (lte == null) return null;
+        if (lte instanceof android.hardware.radio.V1_0.CellIdentityLte) {
+            android.hardware.radio.V1_0.CellIdentityLte ci =
+                    (android.hardware.radio.V1_0.CellIdentityLte) lte;
+            return new CellIdentityLte(ci.ci, ci.pci, ci.tac, ci.earfcn, new int[] {},
+                    CellInfo.UNAVAILABLE, ci.mcc, ci.mnc, "", "", new ArraySet<>(), null);
+        } else if (lte instanceof android.hardware.radio.V1_2.CellIdentityLte) {
+            android.hardware.radio.V1_2.CellIdentityLte ci =
+                    (android.hardware.radio.V1_2.CellIdentityLte) lte;
+            return new CellIdentityLte(ci.base.ci, ci.base.pci, ci.base.tac, ci.base.earfcn,
+                    new int[] {}, ci.bandwidth, ci.base.mcc, ci.base.mnc,
+                    ci.operatorNames.alphaLong, ci.operatorNames.alphaShort, new ArraySet<>(),
+                    null);
+        } else if (lte instanceof android.hardware.radio.V1_5.CellIdentityLte) {
+            android.hardware.radio.V1_5.CellIdentityLte ci =
+                    (android.hardware.radio.V1_5.CellIdentityLte) lte;
+            return new CellIdentityLte(ci.base.base.ci, ci.base.base.pci, ci.base.base.tac,
+                    ci.base.base.earfcn, ci.bands.stream().mapToInt(Integer::intValue).toArray(),
+                    ci.base.bandwidth, ci.base.base.mcc, ci.base.base.mnc,
+                    ci.base.operatorNames.alphaLong, ci.base.operatorNames.alphaShort,
+                    ci.additionalPlmns, convertHalClosedSubscriberGroupInfo(ci.optionalCsgInfo));
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Convert a CellIdentityLte defined in CellIdentityLte.aidl to CellIdentityLte
+     * @param cid CellIdentityLte defined in CellIdentityLte.aidl
+     * @return The converted CellIdentityLte
+     */
+    public static CellIdentityLte convertHalCellIdentityLte(
+            android.hardware.radio.network.CellIdentityLte cid) {
+        return new CellIdentityLte(cid.ci, cid.pci, cid.tac, cid.earfcn, cid.bands, cid.bandwidth,
+                cid.mcc, cid.mnc, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort,
+                primitiveArrayToArrayList(cid.additionalPlmns),
+                convertHalClosedSubscriberGroupInfo(cid.csgInfo));
+    }
+
+    /**
+     * Convert a CellIdentityWcdma defined in radio/1.0, 1.2, 1.5/types.hal to CellIdentityWcdma
+     * @param wcdma CellIdentityWcdma defined in radio/1.0, 1.2, 1.5/types.hal
+     * @return The converted CellIdentityWcdma
+     */
+    public static CellIdentityWcdma convertHalCellIdentityWcdma(Object wcdma) {
+        if (wcdma == null) return null;
+        if (wcdma instanceof android.hardware.radio.V1_0.CellIdentityWcdma) {
+            android.hardware.radio.V1_0.CellIdentityWcdma ci =
+                    (android.hardware.radio.V1_0.CellIdentityWcdma) wcdma;
+            return new CellIdentityWcdma(ci.lac, ci.cid, ci.psc, ci.uarfcn, ci.mcc, ci.mnc, "", "",
+                    new ArraySet<>(), null);
+        } else if (wcdma instanceof android.hardware.radio.V1_2.CellIdentityWcdma) {
+            android.hardware.radio.V1_2.CellIdentityWcdma ci =
+                    (android.hardware.radio.V1_2.CellIdentityWcdma) wcdma;
+            return new CellIdentityWcdma(ci.base.lac, ci.base.cid, ci.base.psc, ci.base.uarfcn,
+                    ci.base.mcc, ci.base.mnc, ci.operatorNames.alphaLong,
+                    ci.operatorNames.alphaShort, new ArraySet<>(), null);
+        } else if (wcdma instanceof android.hardware.radio.V1_5.CellIdentityWcdma) {
+            android.hardware.radio.V1_5.CellIdentityWcdma ci =
+                    (android.hardware.radio.V1_5.CellIdentityWcdma) wcdma;
+            return new CellIdentityWcdma(ci.base.base.lac, ci.base.base.cid, ci.base.base.psc,
+                    ci.base.base.uarfcn, ci.base.base.mcc, ci.base.base.mnc,
+                    ci.base.operatorNames.alphaLong, ci.base.operatorNames.alphaShort,
+                    ci.additionalPlmns, convertHalClosedSubscriberGroupInfo(ci.optionalCsgInfo));
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Convert a CellIdentityWcdma defined in CellIdentityWcdma.aidl to CellIdentityWcdma
+     * @param cid CellIdentityWcdma defined in CellIdentityWcdma.aidl
+     * @return The converted CellIdentityWcdma
+     */
+    public static CellIdentityWcdma convertHalCellIdentityWcdma(
+            android.hardware.radio.network.CellIdentityWcdma cid) {
+        return new CellIdentityWcdma(cid.lac, cid.cid, cid.psc, cid.uarfcn, cid.mcc, cid.mnc,
+                cid.operatorNames.alphaLong, cid.operatorNames.alphaShort,
+                primitiveArrayToArrayList(cid.additionalPlmns),
+                convertHalClosedSubscriberGroupInfo(cid.csgInfo));
+    }
+
+    /**
+     * Convert a CellIdentityTdscdma defined in radio/1.0, 1.2, 1.5/types.hal to CellIdentityTdscdma
+     * @param tdscdma CellIdentityTdscdma defined in radio/1.0, 1.2, 1.5/types.hal
+     * @return The converted CellIdentityTdscdma
+     */
+    public static CellIdentityTdscdma convertHalCellIdentityTdscdma(Object tdscdma) {
+        if (tdscdma == null) return null;
+        if (tdscdma instanceof android.hardware.radio.V1_0.CellIdentityTdscdma) {
+            android.hardware.radio.V1_0.CellIdentityTdscdma ci =
+                    (android.hardware.radio.V1_0.CellIdentityTdscdma) tdscdma;
+            return new CellIdentityTdscdma(ci.mcc, ci.mnc, ci.lac, ci.cid, ci.cpid,
+                    CellInfo.UNAVAILABLE, "", "", Collections.emptyList(), null);
+        } else if (tdscdma instanceof android.hardware.radio.V1_2.CellIdentityTdscdma) {
+            android.hardware.radio.V1_2.CellIdentityTdscdma ci =
+                    (android.hardware.radio.V1_2.CellIdentityTdscdma) tdscdma;
+            return new CellIdentityTdscdma(ci.base.mcc, ci.base.mnc, ci.base.lac, ci.base.cid,
+                    ci.base.cpid, ci.uarfcn, ci.operatorNames.alphaLong,
+                    ci.operatorNames.alphaShort, Collections.emptyList(), null);
+        } else if (tdscdma instanceof android.hardware.radio.V1_5.CellIdentityTdscdma) {
+            android.hardware.radio.V1_5.CellIdentityTdscdma ci =
+                    (android.hardware.radio.V1_5.CellIdentityTdscdma) tdscdma;
+            return new CellIdentityTdscdma(ci.base.base.mcc, ci.base.base.mnc, ci.base.base.lac,
+                    ci.base.base.cid, ci.base.base.cpid, ci.base.uarfcn,
+                    ci.base.operatorNames.alphaLong, ci.base.operatorNames.alphaShort,
+                    ci.additionalPlmns, convertHalClosedSubscriberGroupInfo(ci.optionalCsgInfo));
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Convert a CellIdentityTdscdma defined in CellIdentityTdscdma.aidl to CellIdentityTdscdma
+     * @param cid CellIdentityTdscdma defined in radio/1.0, 1.2, 1.5/types.hal
+     * @return The converted CellIdentityTdscdma
+     */
+    public static CellIdentityTdscdma convertHalCellIdentityTdscdma(
+            android.hardware.radio.network.CellIdentityTdscdma cid) {
+        return new CellIdentityTdscdma(cid.mcc, cid.mnc, cid.lac, cid.cid, cid.cpid, cid.uarfcn,
+                cid.operatorNames.alphaLong, cid.operatorNames.alphaShort,
+                primitiveArrayToArrayList(cid.additionalPlmns),
+                convertHalClosedSubscriberGroupInfo(cid.csgInfo));
+    }
+
+    /**
+     * Convert a CellIdentityNr defined in radio/1.4, 1.5/types.hal to CellIdentityNr
+     * @param nr CellIdentityNr defined in radio/1.4 1.5/types.hal
+     * @return The converted CellIdentityNr
+     */
+    public static CellIdentityNr convertHalCellIdentityNr(Object nr) {
+        if (nr == null) return null;
+        if (nr instanceof android.hardware.radio.V1_4.CellIdentityNr) {
+            android.hardware.radio.V1_4.CellIdentityNr ci =
+                    (android.hardware.radio.V1_4.CellIdentityNr) nr;
+            return new CellIdentityNr(ci.pci, ci.tac, ci.nrarfcn, new int[] {}, ci.mcc, ci.mnc,
+                    ci.nci, ci.operatorNames.alphaLong, ci.operatorNames.alphaShort,
+                    new ArraySet<>());
+        } else if (nr instanceof android.hardware.radio.V1_5.CellIdentityNr) {
+            android.hardware.radio.V1_5.CellIdentityNr ci =
+                    (android.hardware.radio.V1_5.CellIdentityNr) nr;
+            return new CellIdentityNr(ci.base.pci, ci.base.tac, ci.base.nrarfcn,
+                    ci.bands.stream().mapToInt(Integer::intValue).toArray(), ci.base.mcc,
+                    ci.base.mnc, ci.base.nci, ci.base.operatorNames.alphaLong,
+                    ci.base.operatorNames.alphaShort, ci.additionalPlmns);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Convert a CellIdentityNr defined in CellIdentityNr.aidl to CellIdentityNr
+     * @param cid CellIdentityNr defined in CellIdentityNr.aidl
+     * @return The converted CellIdentityNr
+     */
+    public static CellIdentityNr convertHalCellIdentityNr(
+            android.hardware.radio.network.CellIdentityNr cid) {
+        return new CellIdentityNr(cid.pci, cid.tac, cid.nrarfcn, cid.bands, cid.mcc, cid.mnc,
+                cid.nci, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort,
+                primitiveArrayToArrayList(cid.additionalPlmns));
+    }
+
+    /**
+     * Convert a SignalStrength defined in radio/1.0, 1.2, 1.4, 1.6/types.hal to SignalStrength
+     * @param ss SignalStrength defined in radio/1.0, 1.2, 1.4, 1.6/types.hal
+     * @return The converted SignalStrength
+     */
+    public static SignalStrength convertHalSignalStrength(Object ss) {
+        if (ss == null) return null;
+        if (ss instanceof android.hardware.radio.V1_0.SignalStrength) {
+            android.hardware.radio.V1_0.SignalStrength signalStrength =
+                    (android.hardware.radio.V1_0.SignalStrength) ss;
+            return new SignalStrength(
+                    RILUtils.convertHalCdmaSignalStrength(signalStrength.cdma, signalStrength.evdo),
+                    RILUtils.convertHalGsmSignalStrength(signalStrength.gw),
+                    new CellSignalStrengthWcdma(),
+                    RILUtils.convertHalTdscdmaSignalStrength(signalStrength.tdScdma),
+                    RILUtils.convertHalLteSignalStrength(signalStrength.lte),
+                    new CellSignalStrengthNr());
+        } else if (ss instanceof android.hardware.radio.V1_2.SignalStrength) {
+            android.hardware.radio.V1_2.SignalStrength signalStrength =
+                    (android.hardware.radio.V1_2.SignalStrength) ss;
+            return new SignalStrength(
+                    RILUtils.convertHalCdmaSignalStrength(signalStrength.cdma, signalStrength.evdo),
+                    RILUtils.convertHalGsmSignalStrength(signalStrength.gsm),
+                    RILUtils.convertHalWcdmaSignalStrength(signalStrength.wcdma),
+                    RILUtils.convertHalTdscdmaSignalStrength(signalStrength.tdScdma),
+                    RILUtils.convertHalLteSignalStrength(signalStrength.lte),
+                    new CellSignalStrengthNr());
+        } else if (ss instanceof android.hardware.radio.V1_4.SignalStrength) {
+            android.hardware.radio.V1_4.SignalStrength signalStrength =
+                    (android.hardware.radio.V1_4.SignalStrength) ss;
+            return new SignalStrength(
+                    RILUtils.convertHalCdmaSignalStrength(signalStrength.cdma, signalStrength.evdo),
+                    RILUtils.convertHalGsmSignalStrength(signalStrength.gsm),
+                    RILUtils.convertHalWcdmaSignalStrength(signalStrength.wcdma),
+                    RILUtils.convertHalTdscdmaSignalStrength(signalStrength.tdscdma),
+                    RILUtils.convertHalLteSignalStrength(signalStrength.lte),
+                    RILUtils.convertHalNrSignalStrength(signalStrength.nr));
+        } else if (ss instanceof android.hardware.radio.V1_6.SignalStrength) {
+            android.hardware.radio.V1_6.SignalStrength signalStrength =
+                    (android.hardware.radio.V1_6.SignalStrength) ss;
+            return new SignalStrength(
+                    RILUtils.convertHalCdmaSignalStrength(signalStrength.cdma, signalStrength.evdo),
+                    RILUtils.convertHalGsmSignalStrength(signalStrength.gsm),
+                    RILUtils.convertHalWcdmaSignalStrength(signalStrength.wcdma),
+                    RILUtils.convertHalTdscdmaSignalStrength(signalStrength.tdscdma),
+                    RILUtils.convertHalLteSignalStrength(signalStrength.lte),
+                    RILUtils.convertHalNrSignalStrength(signalStrength.nr));
+        }
+        return null;
+    }
+
+    /**
+     * Convert a SignalStrength defined in SignalStrength.aidl to SignalStrength
+     * @param signalStrength SignalStrength defined in SignalStrength.aidl
+     * @return The converted SignalStrength
+     */
+    public static SignalStrength convertHalSignalStrength(
+            android.hardware.radio.network.SignalStrength signalStrength) {
+        return new SignalStrength(
+                RILUtils.convertHalCdmaSignalStrength(signalStrength.cdma, signalStrength.evdo),
+                RILUtils.convertHalGsmSignalStrength(signalStrength.gsm),
+                RILUtils.convertHalWcdmaSignalStrength(signalStrength.wcdma),
+                RILUtils.convertHalTdscdmaSignalStrength(signalStrength.tdscdma),
+                RILUtils.convertHalLteSignalStrength(signalStrength.lte),
+                RILUtils.convertHalNrSignalStrength(signalStrength.nr));
+    }
+
+    /**
+     * Convert a GsmSignalStrength defined in radio/1.0/types.hal to CellSignalStrengthGsm
+     * @param ss GsmSignalStrength defined in radio/1.0/types.hal
+     * @return The converted CellSignalStrengthGsm
+     */
+    public static CellSignalStrengthGsm convertHalGsmSignalStrength(
+            android.hardware.radio.V1_0.GsmSignalStrength ss) {
+        CellSignalStrengthGsm ret = new CellSignalStrengthGsm(
+                CellSignalStrength.getRssiDbmFromAsu(ss.signalStrength), ss.bitErrorRate,
+                ss.timingAdvance);
+        if (ret.getRssi() == CellInfo.UNAVAILABLE) {
+            ret.setDefaultValues();
+            ret.updateLevel(null, null);
+        }
+        return ret;
+    }
+
+    /**
+     * Convert a GsmSignalStrength defined in GsmSignalStrength.aidl to CellSignalStrengthGsm
+     * @param ss GsmSignalStrength defined in GsmSignalStrength.aidl
+     * @return The converted CellSignalStrengthGsm
+     */
+    public static CellSignalStrengthGsm convertHalGsmSignalStrength(
+            android.hardware.radio.network.GsmSignalStrength ss) {
+        CellSignalStrengthGsm ret = new CellSignalStrengthGsm(
+                CellSignalStrength.getRssiDbmFromAsu(ss.signalStrength), ss.bitErrorRate,
+                ss.timingAdvance);
+        if (ret.getRssi() == CellInfo.UNAVAILABLE) {
+            ret.setDefaultValues();
+            ret.updateLevel(null, null);
+        }
+        return ret;
+    }
+
+    /**
+     * Convert a CdmaSignalStrength and EvdoSignalStrength defined in radio/1.0/types.hal to
+     * CellSignalStrengthCdma
+     * @param cdma CdmaSignalStrength defined in radio/1.0/types.hal
+     * @param evdo EvdoSignalStrength defined in radio/1.0/types.hal
+     * @return The converted CellSignalStrengthCdma
+     */
+    public static CellSignalStrengthCdma convertHalCdmaSignalStrength(
+            android.hardware.radio.V1_0.CdmaSignalStrength cdma,
+            android.hardware.radio.V1_0.EvdoSignalStrength evdo) {
+        return new CellSignalStrengthCdma(-cdma.dbm, -cdma.ecio, -evdo.dbm, -evdo.ecio,
+                evdo.signalNoiseRatio);
+    }
+
+    /**
+     * Convert a CdmaSignalStrength and EvdoSignalStrength defined in radio/network to
+     * CellSignalStrengthCdma
+     * @param cdma CdmaSignalStrength defined in CdmaSignalStrength.aidl
+     * @param evdo EvdoSignalStrength defined in EvdoSignalStrength.aidl
+     * @return The converted CellSignalStrengthCdma
+     */
+    public static CellSignalStrengthCdma convertHalCdmaSignalStrength(
+            android.hardware.radio.network.CdmaSignalStrength cdma,
+            android.hardware.radio.network.EvdoSignalStrength evdo) {
+        return new CellSignalStrengthCdma(-cdma.dbm, -cdma.ecio, -evdo.dbm, -evdo.ecio,
+                evdo.signalNoiseRatio);
+    }
+
+    /**
+     * Convert a LteSignalStrength defined in radio/1.0, 1.6/types.hal to CellSignalStrengthLte
+     * @param lte LteSignalStrength defined in radio/1.0, 1.6/types.hal
+     * @return The converted CellSignalStrengthLte
+     */
+    public static CellSignalStrengthLte convertHalLteSignalStrength(Object lte) {
+        if (lte == null) return null;
+        if (lte instanceof android.hardware.radio.V1_0.LteSignalStrength) {
+            android.hardware.radio.V1_0.LteSignalStrength ss =
+                    (android.hardware.radio.V1_0.LteSignalStrength) lte;
+            return new CellSignalStrengthLte(
+                    CellSignalStrengthLte.convertRssiAsuToDBm(ss.signalStrength),
+                    ss.rsrp != CellInfo.UNAVAILABLE ? -ss.rsrp : ss.rsrp,
+                    ss.rsrq != CellInfo.UNAVAILABLE ? -ss.rsrq : ss.rsrq,
+                    CellSignalStrengthLte.convertRssnrUnitFromTenDbToDB(ss.rssnr), ss.cqi,
+                    ss.timingAdvance);
+        } else if (lte instanceof android.hardware.radio.V1_6.LteSignalStrength) {
+            android.hardware.radio.V1_6.LteSignalStrength ss =
+                    (android.hardware.radio.V1_6.LteSignalStrength) lte;
+            return new CellSignalStrengthLte(
+                    CellSignalStrengthLte.convertRssiAsuToDBm(ss.base.signalStrength),
+                    ss.base.rsrp != CellInfo.UNAVAILABLE ? -ss.base.rsrp : ss.base.rsrp,
+                    ss.base.rsrq != CellInfo.UNAVAILABLE ? -ss.base.rsrq : ss.base.rsrq,
+                    CellSignalStrengthLte.convertRssnrUnitFromTenDbToDB(ss.base.rssnr),
+                    ss.cqiTableIndex, ss.base.cqi, ss.base.timingAdvance);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Convert a LteSignalStrength defined in LteSignalStrength.aidl to CellSignalStrengthLte
+     * @param ss LteSignalStrength defined in LteSignalStrength.aidl
+     * @return The converted CellSignalStrengthLte
+     */
+    public static CellSignalStrengthLte convertHalLteSignalStrength(
+            android.hardware.radio.network.LteSignalStrength ss) {
+        return new CellSignalStrengthLte(
+                CellSignalStrengthLte.convertRssiAsuToDBm(ss.signalStrength),
+                ss.rsrp != CellInfo.UNAVAILABLE ? -ss.rsrp : ss.rsrp,
+                ss.rsrq != CellInfo.UNAVAILABLE ? -ss.rsrq : ss.rsrq,
+                CellSignalStrengthLte.convertRssnrUnitFromTenDbToDB(ss.rssnr), ss.cqiTableIndex,
+                ss.cqi, ss.timingAdvance);
+    }
+
+    /**
+     * Convert a WcdmaSignalStrength defined in radio/1.0, 1.2/types.hal to CellSignalStrengthWcdma
+     * @param wcdma WcdmaSignalStrength defined in radio/1.0, 1.2/types.hal
+     * @return The converted CellSignalStrengthWcdma
+     */
+    public static CellSignalStrengthWcdma convertHalWcdmaSignalStrength(Object wcdma) {
+        if (wcdma == null) return null;
+        CellSignalStrengthWcdma ret = null;
+        if (wcdma instanceof android.hardware.radio.V1_0.WcdmaSignalStrength) {
+            android.hardware.radio.V1_0.WcdmaSignalStrength ss =
+                    (android.hardware.radio.V1_0.WcdmaSignalStrength) wcdma;
+            ret = new CellSignalStrengthWcdma(
+                    CellSignalStrength.getRssiDbmFromAsu(ss.signalStrength), ss.bitErrorRate,
+                    CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE);
+        } else if (wcdma instanceof android.hardware.radio.V1_2.WcdmaSignalStrength) {
+            android.hardware.radio.V1_2.WcdmaSignalStrength ss =
+                    (android.hardware.radio.V1_2.WcdmaSignalStrength) wcdma;
+            ret = new CellSignalStrengthWcdma(
+                    CellSignalStrength.getRssiDbmFromAsu(ss.base.signalStrength),
+                    ss.base.bitErrorRate, CellSignalStrength.getRscpDbmFromAsu(ss.rscp),
+                    CellSignalStrength.getEcNoDbFromAsu(ss.ecno));
+        }
+        if (ret != null && ret.getRssi() == CellInfo.UNAVAILABLE
+                && ret.getRscp() == CellInfo.UNAVAILABLE) {
+            ret.setDefaultValues();
+            ret.updateLevel(null, null);
+        }
+        return ret;
+    }
+
+    /**
+     * Convert a WcdmaSignalStrength defined in WcdmaSignalStrength.aidl to CellSignalStrengthWcdma
+     * @param ss WcdmaSignalStrength defined in WcdmaSignalStrength.aidl
+     * @return The converted CellSignalStrengthWcdma
+     */
+    public static CellSignalStrengthWcdma convertHalWcdmaSignalStrength(
+            android.hardware.radio.network.WcdmaSignalStrength ss) {
+        CellSignalStrengthWcdma ret = new CellSignalStrengthWcdma(
+                CellSignalStrength.getRssiDbmFromAsu(ss.signalStrength),
+                ss.bitErrorRate, CellSignalStrength.getRscpDbmFromAsu(ss.rscp),
+                CellSignalStrength.getEcNoDbFromAsu(ss.ecno));
+        if (ret.getRssi() == CellInfo.UNAVAILABLE && ret.getRscp() == CellInfo.UNAVAILABLE) {
+            ret.setDefaultValues();
+            ret.updateLevel(null, null);
+        }
+        return ret;
+    }
+
+    /**
+     * Convert a TdScdmaSignalStrength defined in radio/1.0/types.hal or TdscdmaSignalStrength
+     * defined in radio/1.2/types.hal to CellSignalStrengthTdscdma
+     * @param tdscdma TdScdmaSignalStrength defined in radio/1.0/types.hal or TdscdmaSignalStrength
+     *        defined in radio/1.2/types.hal
+     * @return The converted CellSignalStrengthTdscdma
+     */
+    public static CellSignalStrengthTdscdma convertHalTdscdmaSignalStrength(Object tdscdma) {
+        if (tdscdma == null) return null;
+        CellSignalStrengthTdscdma ret = null;
+        if (tdscdma instanceof android.hardware.radio.V1_0.TdScdmaSignalStrength) {
+            android.hardware.radio.V1_0.TdScdmaSignalStrength ss =
+                    (android.hardware.radio.V1_0.TdScdmaSignalStrength) tdscdma;
+            ret = new CellSignalStrengthTdscdma(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+                    ss.rscp != CellInfo.UNAVAILABLE ? -ss.rscp : ss.rscp);
+        } else if (tdscdma instanceof android.hardware.radio.V1_2.TdscdmaSignalStrength) {
+            android.hardware.radio.V1_2.TdscdmaSignalStrength ss =
+                    (android.hardware.radio.V1_2.TdscdmaSignalStrength) tdscdma;
+            ret = new CellSignalStrengthTdscdma(
+                    CellSignalStrength.getRssiDbmFromAsu(ss.signalStrength), ss.bitErrorRate,
+                    CellSignalStrength.getRscpDbmFromAsu(ss.rscp));
+        }
+        if (ret != null && ret.getRssi() == CellInfo.UNAVAILABLE
+                && ret.getRscp() == CellInfo.UNAVAILABLE) {
+            ret.setDefaultValues();
+            ret.updateLevel(null, null);
+        }
+        return ret;
+    }
+
+    /**
+     * Convert a TdscdmaSignalStrength defined in TdscdmaSignalStrength.aidl to
+     * CellSignalStrengthTdscdma
+     * @param ss TdscdmaSignalStrength defined in TdscdmaSignalStrength.aidl
+     * @return The converted CellSignalStrengthTdscdma
+     */
+    public static CellSignalStrengthTdscdma convertHalTdscdmaSignalStrength(
+            android.hardware.radio.network.TdscdmaSignalStrength ss) {
+        CellSignalStrengthTdscdma ret = new CellSignalStrengthTdscdma(
+                CellSignalStrength.getRssiDbmFromAsu(ss.signalStrength),
+                ss.bitErrorRate, CellSignalStrength.getRscpDbmFromAsu(ss.rscp));
+        if (ret.getRssi() == CellInfo.UNAVAILABLE && ret.getRscp() == CellInfo.UNAVAILABLE) {
+            ret.setDefaultValues();
+            ret.updateLevel(null, null);
+        }
+        return ret;
+    }
+
+    /**
+     * Convert a NrSignalStrength defined in radio/1.4, 1.6/types.hal to CellSignalStrengthNr
+     * @param nr NrSignalStrength defined in radio/1.4, 1.6/types.hal
+     * @return The converted CellSignalStrengthNr
+     */
+    public static CellSignalStrengthNr convertHalNrSignalStrength(Object nr) {
+        if (nr == null) return null;
+        if (nr instanceof android.hardware.radio.V1_4.NrSignalStrength) {
+            android.hardware.radio.V1_4.NrSignalStrength ss =
+                    (android.hardware.radio.V1_4.NrSignalStrength) nr;
+            return new CellSignalStrengthNr(CellSignalStrengthNr.flip(ss.csiRsrp),
+                    CellSignalStrengthNr.flip(ss.csiRsrq), ss.csiSinr,
+                    CellSignalStrengthNr.flip(ss.ssRsrp), CellSignalStrengthNr.flip(ss.ssRsrq),
+                    ss.ssSinr);
+        } else if (nr instanceof android.hardware.radio.V1_6.NrSignalStrength) {
+            android.hardware.radio.V1_6.NrSignalStrength ss =
+                    (android.hardware.radio.V1_6.NrSignalStrength) nr;
+            return new CellSignalStrengthNr(CellSignalStrengthNr.flip(ss.base.csiRsrp),
+                    CellSignalStrengthNr.flip(ss.base.csiRsrq), ss.base.csiSinr,
+                    ss.csiCqiTableIndex, ss.csiCqiReport, CellSignalStrengthNr.flip(ss.base.ssRsrp),
+                    CellSignalStrengthNr.flip(ss.base.ssRsrq), ss.base.ssSinr);
+        }
+        return null;
+    }
+
+    /**
+     * Convert a NrSignalStrength defined in NrSignalStrength.aidl to CellSignalStrengthNr
+     * @param ss NrSignalStrength defined in NrSignalStrength.aidl
+     * @return The converted CellSignalStrengthNr
+     */
+    public static CellSignalStrengthNr convertHalNrSignalStrength(
+            android.hardware.radio.network.NrSignalStrength ss) {
+        return new CellSignalStrengthNr(CellSignalStrengthNr.flip(ss.csiRsrp),
+                CellSignalStrengthNr.flip(ss.csiRsrq), ss.csiSinr, ss.csiCqiTableIndex,
+                primitiveArrayToArrayList(ss.csiCqiReport), CellSignalStrengthNr.flip(ss.ssRsrp),
+                CellSignalStrengthNr.flip(ss.ssRsrq), ss.ssSinr);
+    }
+
+    private static ClosedSubscriberGroupInfo convertHalClosedSubscriberGroupInfo(
+            android.hardware.radio.V1_5.OptionalCsgInfo optionalCsgInfo) {
+        android.hardware.radio.V1_5.ClosedSubscriberGroupInfo csgInfo =
+                optionalCsgInfo.getDiscriminator()
+                        == android.hardware.radio.V1_5.OptionalCsgInfo.hidl_discriminator.csgInfo
+                        ? optionalCsgInfo.csgInfo() : null;
+        if (csgInfo == null) return null;
+        return new ClosedSubscriberGroupInfo(csgInfo.csgIndication, csgInfo.homeNodebName,
+                csgInfo.csgIdentity);
+    }
+
+    private static ClosedSubscriberGroupInfo convertHalClosedSubscriberGroupInfo(
+            android.hardware.radio.network.ClosedSubscriberGroupInfo csgInfo) {
+        if (csgInfo == null) return null;
+        return new ClosedSubscriberGroupInfo(csgInfo.csgIndication, csgInfo.homeNodebName,
+                csgInfo.csgIdentity);
+    }
+
+    /**
+     * Convert a list of BarringInfo defined in radio/1.5/types.hal to a sparse array of
+     * BarringServiceInfos
+     * @param halBarringInfos List of BarringInfos defined in radio/1.5/types.hal
+     * @return The converted sparse array of BarringServiceInfos
+     */
+    public static SparseArray<BarringInfo.BarringServiceInfo> convertHalBarringInfoList(
+            List<android.hardware.radio.V1_5.BarringInfo> halBarringInfos) {
+        SparseArray<BarringInfo.BarringServiceInfo> serviceInfos = new SparseArray<>();
+        for (android.hardware.radio.V1_5.BarringInfo halBarringInfo : halBarringInfos) {
+            if (halBarringInfo.barringType
+                    == android.hardware.radio.V1_5.BarringInfo.BarringType.CONDITIONAL) {
+                if (halBarringInfo.barringTypeSpecificInfo.getDiscriminator()
+                        != android.hardware.radio.V1_5.BarringInfo.BarringTypeSpecificInfo
+                        .hidl_discriminator.conditional) {
+                    // this is an error case where the barring info is conditional but the
+                    // conditional barring fields weren't included
+                    continue;
+                }
+                android.hardware.radio.V1_5.BarringInfo.BarringTypeSpecificInfo
+                        .Conditional conditionalInfo =
+                        halBarringInfo.barringTypeSpecificInfo.conditional();
+                serviceInfos.put(
+                        halBarringInfo.serviceType, new BarringInfo.BarringServiceInfo(
+                                halBarringInfo.barringType, // will always be CONDITIONAL here
+                                conditionalInfo.isBarred,
+                                conditionalInfo.factor,
+                                conditionalInfo.timeSeconds));
+            } else {
+                // Barring type is either NONE or UNCONDITIONAL
+                serviceInfos.put(
+                        halBarringInfo.serviceType, new BarringInfo.BarringServiceInfo(
+                                halBarringInfo.barringType, false, 0, 0));
+            }
+        }
+        return serviceInfos;
+    }
+
+    /**
+     * Convert a list of BarringInfo defined in BarringInfo.aidl to a sparse array of
+     * BarringServiceInfos
+     * @param halBarringInfos List of BarringInfos defined in BarringInfo.aidl
+     * @return The converted sparse array of BarringServiceInfos
+     */
+    public static SparseArray<BarringInfo.BarringServiceInfo> convertHalBarringInfoList(
+            android.hardware.radio.network.BarringInfo[] halBarringInfos) {
+        SparseArray<BarringInfo.BarringServiceInfo> serviceInfos = new SparseArray<>();
+        for (android.hardware.radio.network.BarringInfo halBarringInfo : halBarringInfos) {
+            if (halBarringInfo.barringType
+                    == android.hardware.radio.network.BarringInfo.BARRING_TYPE_CONDITIONAL) {
+                if (halBarringInfo.barringTypeSpecificInfo == null) {
+                    // this is an error case where the barring info is conditional but the
+                    // conditional barring fields weren't included
+                    continue;
+                }
+                serviceInfos.put(
+                        halBarringInfo.serviceType, new BarringInfo.BarringServiceInfo(
+                                halBarringInfo.barringType, // will always be CONDITIONAL here
+                                halBarringInfo.barringTypeSpecificInfo.isBarred,
+                                halBarringInfo.barringTypeSpecificInfo.factor,
+                                halBarringInfo.barringTypeSpecificInfo.timeSeconds));
+            } else {
+                // Barring type is either NONE or UNCONDITIONAL
+                serviceInfos.put(halBarringInfo.serviceType, new BarringInfo.BarringServiceInfo(
+                        halBarringInfo.barringType, false, 0, 0));
+            }
+        }
+        return serviceInfos;
     }
 
     private static LinkAddress convertToLinkAddress(String addressString) {
@@ -1893,8 +3318,8 @@
     }
 
     /**
-     * Convert RadioState defined in radio/1.0/types.hal to RadioPowerState
-     * @param stateInt Radio state defined in radio/1.0/types.hal
+     * Convert RadioState defined in radio/1.0/types.hal and RadioState.aidl to RadioPowerState
+     * @param stateInt Radio state defined in radio/1.0/types.hal or RadioState.aidl
      * @return The converted {@link Annotation.RadioPowerState RadioPowerState}
      */
     public static @Annotation.RadioPowerState int convertHalRadioState(int stateInt) {
@@ -1994,6 +3419,40 @@
     }
 
     /**
+     * Convert Call defined in Call.aidl to DriverCall
+     * @param halCall Call defined in Call.aidl
+     * @return The converted DriverCall
+     */
+    public static DriverCall convertToDriverCall(android.hardware.radio.voice.Call halCall) {
+        DriverCall dc = new DriverCall();
+        dc.state = DriverCall.stateFromCLCC((int) halCall.state);
+        dc.index = halCall.index;
+        dc.TOA = halCall.toa;
+        dc.isMpty = halCall.isMpty;
+        dc.isMT = halCall.isMT;
+        dc.als = halCall.als;
+        dc.isVoice = halCall.isVoice;
+        dc.isVoicePrivacy = halCall.isVoicePrivacy;
+        dc.number = halCall.number;
+        dc.numberPresentation = DriverCall.presentationFromCLIP((int) halCall.numberPresentation);
+        dc.name = halCall.name;
+        dc.namePresentation = DriverCall.presentationFromCLIP((int) halCall.namePresentation);
+        if (halCall.uusInfo.length == 1) {
+            dc.uusInfo = new UUSInfo();
+            dc.uusInfo.setType(halCall.uusInfo[0].uusType);
+            dc.uusInfo.setDcs(halCall.uusInfo[0].uusDcs);
+            if (!TextUtils.isEmpty(halCall.uusInfo[0].uusData)) {
+                dc.uusInfo.setUserData(halCall.uusInfo[0].uusData.getBytes());
+            }
+        }
+        // Make sure there's a leading + on addresses with a TOA of 145
+        dc.number = PhoneNumberUtils.stringFromStringAndTOA(dc.number, dc.TOA);
+        dc.audioQuality = (int) halCall.audioQuality;
+        dc.forwardedNumber = halCall.forwardedNumber;
+        return dc;
+    }
+
+    /**
      * Convert OperatorStatus defined in radio/1.0/types.hal to OperatorInfo.State
      * @param status Operator status defined in radio/1.0/types.hal
      * @return The converted OperatorStatus as a String
@@ -2041,6 +3500,34 @@
     }
 
     /**
+     * Convert a list of Carriers defined in radio/1.0/types.hal to a list of CarrierIdentifiers
+     * @param carrierList List of Carriers defined in radio/1.0/types.hal
+     * @return The converted list of CarrierIdentifiers
+     */
+    public static List<CarrierIdentifier> convertHalCarrierList(
+            android.hardware.radio.sim.Carrier[] carrierList) {
+        List<CarrierIdentifier> ret = new ArrayList<>();
+        for (int i = 0; i < carrierList.length; i++) {
+            String mcc = carrierList[i].mcc;
+            String mnc = carrierList[i].mnc;
+            String spn = null, imsi = null, gid1 = null, gid2 = null;
+            int matchType = carrierList[i].matchType;
+            String matchData = carrierList[i].matchData;
+            if (matchType == CarrierIdentifier.MatchType.SPN) {
+                spn = matchData;
+            } else if (matchType == CarrierIdentifier.MatchType.IMSI_PREFIX) {
+                imsi = matchData;
+            } else if (matchType == CarrierIdentifier.MatchType.GID1) {
+                gid1 = matchData;
+            } else if (matchType == CarrierIdentifier.MatchType.GID2) {
+                gid2 = matchData;
+            }
+            ret.add(new CarrierIdentifier(mcc, mnc, spn, imsi, gid1, gid2));
+        }
+        return ret;
+    }
+
+    /**
      * Convert CardStatus defined in radio/1.0, 1.5/types.hal to IccCardStatus
      * @param cardStatus CardStatus defined in radio/1.0, 1.5/types.hal
      * @return The converted IccCardStatus
@@ -2083,7 +3570,7 @@
                         rilAppStatus.persoSubstate);
                 appStatus.aid = rilAppStatus.aidPtr;
                 appStatus.app_label = rilAppStatus.appLabelPtr;
-                appStatus.pin1_replaced = rilAppStatus.pin1Replaced;
+                appStatus.pin1_replaced = rilAppStatus.pin1Replaced != 0;
                 appStatus.pin1 = appStatus.PinStateFromRILInt(rilAppStatus.pin1);
                 appStatus.pin2 = appStatus.PinStateFromRILInt(rilAppStatus.pin2);
                 iccCardStatus.mApplications[i] = appStatus;
@@ -2111,7 +3598,7 @@
                         rilAppStatus.persoSubstate);
                 appStatus.aid = rilAppStatus.base.aidPtr;
                 appStatus.app_label = rilAppStatus.base.appLabelPtr;
-                appStatus.pin1_replaced = rilAppStatus.base.pin1Replaced;
+                appStatus.pin1_replaced = rilAppStatus.base.pin1Replaced != 0;
                 appStatus.pin1 = appStatus.PinStateFromRILInt(rilAppStatus.base.pin1);
                 appStatus.pin2 = appStatus.PinStateFromRILInt(rilAppStatus.base.pin2);
                 iccCardStatus.mApplications[i] = appStatus;
@@ -2120,6 +3607,140 @@
         return iccCardStatus;
     }
 
+    /**
+     * Convert CardStatus defined in CardStatus.aidl to IccCardStatus
+     * @param cardStatus CardStatus defined in CardStatus.aidl
+     * @return The converted IccCardStatus
+     */
+    public static IccCardStatus convertHalCardStatus(
+            android.hardware.radio.sim.CardStatus cardStatus) {
+        IccCardStatus iccCardStatus = new IccCardStatus();
+        iccCardStatus.setCardState(cardStatus.cardState);
+        iccCardStatus.setUniversalPinState(cardStatus.universalPinState);
+        iccCardStatus.mGsmUmtsSubscriptionAppIndex = cardStatus.gsmUmtsSubscriptionAppIndex;
+        iccCardStatus.mCdmaSubscriptionAppIndex = cardStatus.cdmaSubscriptionAppIndex;
+        iccCardStatus.mImsSubscriptionAppIndex = cardStatus.imsSubscriptionAppIndex;
+        iccCardStatus.physicalSlotIndex = cardStatus.slotMap.physicalSlotId;
+        iccCardStatus.atr = cardStatus.atr;
+        iccCardStatus.iccid = cardStatus.iccid;
+        iccCardStatus.eid = cardStatus.eid;
+
+        int numApplications = Math.min(cardStatus.applications.length,
+                com.android.internal.telephony.uicc.IccCardStatus.CARD_MAX_APPS);
+        iccCardStatus.mApplications = new IccCardApplicationStatus[numApplications];
+        for (int i = 0; i < numApplications; i++) {
+            android.hardware.radio.sim.AppStatus rilAppStatus = cardStatus.applications[i];
+            IccCardApplicationStatus appStatus = new IccCardApplicationStatus();
+            appStatus.app_type = appStatus.AppTypeFromRILInt(rilAppStatus.appType);
+            appStatus.app_state = appStatus.AppStateFromRILInt(rilAppStatus.appState);
+            appStatus.perso_substate = appStatus.PersoSubstateFromRILInt(
+                    rilAppStatus.persoSubstate);
+            appStatus.aid = rilAppStatus.aidPtr;
+            appStatus.app_label = rilAppStatus.appLabelPtr;
+            appStatus.pin1_replaced = rilAppStatus.pin1Replaced;
+            appStatus.pin1 = appStatus.PinStateFromRILInt(rilAppStatus.pin1);
+            appStatus.pin2 = appStatus.PinStateFromRILInt(rilAppStatus.pin2);
+            iccCardStatus.mApplications[i] = appStatus;
+        }
+        return iccCardStatus;
+    }
+
+    /**
+     * Convert PhonebookCapacity defined in radio/1.6/types.hal to AdnCapacity
+     * @param pbCap PhonebookCapacity defined in radio/1.6/types.hal
+     * @return The converted AdnCapacity
+     */
+    public static AdnCapacity convertHalPhonebookCapacity(
+            android.hardware.radio.V1_6.PhonebookCapacity pbCap) {
+        if (pbCap != null) {
+            return new AdnCapacity(pbCap.maxAdnRecords, pbCap.usedAdnRecords, pbCap.maxEmailRecords,
+                    pbCap.usedEmailRecords, pbCap.maxAdditionalNumberRecords,
+                    pbCap.usedAdditionalNumberRecords, pbCap.maxNameLen, pbCap.maxNumberLen,
+                    pbCap.maxEmailLen, pbCap.maxAdditionalNumberLen);
+        }
+        return null;
+    }
+
+    /**
+     * Convert PhonebookCapacity defined in PhonebookCapacity.aidl to AdnCapacity
+     * @param pbCap PhonebookCapacity defined in PhonebookCapacity.aidl
+     * @return The converted AdnCapacity
+     */
+    public static AdnCapacity convertHalPhonebookCapacity(
+            android.hardware.radio.sim.PhonebookCapacity pbCap) {
+        if (pbCap != null) {
+            return new AdnCapacity(pbCap.maxAdnRecords, pbCap.usedAdnRecords, pbCap.maxEmailRecords,
+                    pbCap.usedEmailRecords, pbCap.maxAdditionalNumberRecords,
+                    pbCap.usedAdditionalNumberRecords, pbCap.maxNameLen, pbCap.maxNumberLen,
+                    pbCap.maxEmailLen, pbCap.maxAdditionalNumberLen);
+        }
+        return null;
+    }
+
+    /**
+     * Convert PhonebookRecordInfo defined in radio/1.6/types.hal to SimPhonebookRecord
+     * @param recInfo PhonebookRecordInfo defined in radio/1.6/types.hal
+     * @return The converted SimPhonebookRecord
+     */
+    public static SimPhonebookRecord convertHalPhonebookRecordInfo(
+            android.hardware.radio.V1_6.PhonebookRecordInfo recInfo) {
+        String[] emails = recInfo.emails == null ? null
+                : recInfo.emails.toArray(new String[recInfo.emails.size()]);
+        String[] numbers = recInfo.additionalNumbers == null ? null
+                : recInfo.additionalNumbers.toArray(new String[recInfo.additionalNumbers.size()]);
+        return new SimPhonebookRecord(recInfo.recordId, recInfo.name, recInfo.number, emails,
+                numbers);
+    }
+
+    /**
+     * Convert PhonebookRecordInfo defined in PhonebookRecordInfo.aidl to SimPhonebookRecord
+     * @param recInfo PhonebookRecordInfo defined in PhonebookRecordInfo.aidl
+     * @return The converted SimPhonebookRecord
+     */
+    public static SimPhonebookRecord convertHalPhonebookRecordInfo(
+            android.hardware.radio.sim.PhonebookRecordInfo recInfo) {
+        return new SimPhonebookRecord(recInfo.recordId, recInfo.name, recInfo.number,
+                recInfo.emails, recInfo.additionalNumbers);
+    }
+
+    /**
+     * Convert SimPhonebookRecord to PhonebookRecordInfo defined in radio/1.6/types.hal
+     * @param record SimPhonebookRecord to convert
+     * @return The converted PhonebookRecordInfo defined in radio/1.6/types.hal
+     */
+    public static android.hardware.radio.V1_6.PhonebookRecordInfo convertToHalPhonebookRecordInfo(
+            SimPhonebookRecord record) {
+        android.hardware.radio.V1_6.PhonebookRecordInfo pbRecordInfo =
+                new android.hardware.radio.V1_6.PhonebookRecordInfo();
+        pbRecordInfo.recordId = record.getRecordIndex();
+        pbRecordInfo.name = convertNullToEmptyString(record.getAlphaTag());
+        pbRecordInfo.number = convertNullToEmptyString(
+                convertToHalPhonebookRecordInfoNumber(record.getNumber()));
+        if (record.getEmails() != null) {
+            for (String email : record.getEmails()) {
+                pbRecordInfo.emails.add(email);
+            }
+        }
+        if (record.getAdditionalNumbers() != null) {
+            for (String addNum : record.getAdditionalNumbers()) {
+                pbRecordInfo.additionalNumbers.add(convertToHalPhonebookRecordInfoNumber(addNum));
+            }
+        }
+        return pbRecordInfo;
+    }
+
+    /**
+     * Convert the GSM pause/wild/wait character to the phone number in the SIM PhonebookRecordInfo
+     * number format
+     * @param input GSM pause/wild/wait character
+     * @return The converted PhonebookRecordInfo number
+     */
+    private static String convertToHalPhonebookRecordInfoNumber(String input) {
+        return input == null ? null : input.replace(PhoneNumberUtils.WAIT, 'e')
+                .replace(PhoneNumberUtils.PAUSE, 'T')
+                .replace(PhoneNumberUtils.WILD, '?');
+    }
+
     /** Append the data to the end of an ArrayList */
     public static void appendPrimitiveArrayToArrayList(byte[] src, ArrayList<Byte> dst) {
         for (byte b : src) {
diff --git a/src/java/com/android/internal/telephony/RadioIndication.java b/src/java/com/android/internal/telephony/RadioIndication.java
index 89603b1..ba74d6a 100644
--- a/src/java/com/android/internal/telephony/RadioIndication.java
+++ b/src/java/com/android/internal/telephony/RadioIndication.java
@@ -109,7 +109,6 @@
 
 import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
 import com.android.internal.telephony.cdma.CdmaInformationRecords;
-import com.android.internal.telephony.cdma.SmsMessageConverter;
 import com.android.internal.telephony.dataconnection.KeepaliveStatus;
 import com.android.internal.telephony.gsm.SsData;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
@@ -242,7 +241,7 @@
                                       android.hardware.radio.V1_0.SignalStrength signalStrength) {
         mRil.processIndication(indicationType);
 
-        SignalStrength ssInitial = new SignalStrength(signalStrength);
+        SignalStrength ssInitial = RILUtils.convertHalSignalStrength(signalStrength);
 
         SignalStrength ss = mRil.fixupSignalStrength10(ssInitial);
         // Note this is set to "verbose" because it happens frequently
@@ -292,7 +291,7 @@
                                       android.hardware.radio.V1_2.SignalStrength signalStrength) {
         mRil.processIndication(indicationType);
 
-        SignalStrength ss = new SignalStrength(signalStrength);
+        SignalStrength ss = RILUtils.convertHalSignalStrength(signalStrength);
         // Note this is set to "verbose" because it happens frequently
         if (RIL.RILJ_LOGV) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss);
 
@@ -309,7 +308,7 @@
 
         mRil.processIndication(indicationType);
 
-        SignalStrength ss = new SignalStrength(signalStrength);
+        SignalStrength ss = RILUtils.convertHalSignalStrength(signalStrength);
 
         if (RIL.RILJ_LOGV) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss);
 
@@ -326,7 +325,7 @@
 
         mRil.processIndication(indicationType);
 
-        SignalStrength ss = new SignalStrength(signalStrength);
+        SignalStrength ss = RILUtils.convertHalSignalStrength(signalStrength);
 
         if (RIL.RILJ_LOGV) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss);
 
@@ -367,6 +366,7 @@
      */
     public void currentEmergencyNumberList(int indicationType,
             ArrayList<android.hardware.radio.V1_4.EmergencyNumber> emergencyNumberList) {
+        mRil.processIndication(indicationType);
         List<EmergencyNumber> response = new ArrayList<>(emergencyNumberList.size());
 
         for (android.hardware.radio.V1_4.EmergencyNumber emergencyNumberHal
@@ -535,9 +535,7 @@
 
         if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_CDMA_NEW_SMS);
 
-        // todo: conversion from CdmaSmsMessage to SmsMessage should be contained in this class so
-        // that usage of auto-generated HAL classes is limited to this file
-        SmsMessage sms = SmsMessageConverter.newSmsMessageFromCdmaSmsMessage(msg);
+        SmsMessage sms = new SmsMessage(RILUtils.convertHalCdmaSmsMessage(msg));
         if (mRil.mCdmaSmsRegistrant != null) {
             mRil.mCdmaSmsRegistrant.notifyRegistrant(new AsyncResult(null, sms, null));
         }
@@ -1068,24 +1066,24 @@
     }
 
     /**
-     * Indicates the content of all the used records in the SIM phonebook..
+     * Indicates the content of all the used records in the SIM phonebook.
      * @param indicationType RadioIndicationType
+     * @param status Status of PbReceivedStatus
      * @param records Content of the SIM phonebook records
      */
     public void simPhonebookRecordsReceived(int indicationType, byte status,
             ArrayList<PhonebookRecordInfo> records) {
         mRil.processIndication(indicationType);
 
-        List<SimPhonebookRecord> simPhonebookRecords = new ArrayList<SimPhonebookRecord>();
+        List<SimPhonebookRecord> simPhonebookRecords = new ArrayList<>();
 
         for (PhonebookRecordInfo record : records) {
-            simPhonebookRecords.add(new SimPhonebookRecord(record));
+            simPhonebookRecords.add(RILUtils.convertHalPhonebookRecordInfo(record));
         }
 
         if (RIL.RILJ_LOGD) {
             mRil.unsljLogRet(RIL_UNSOL_RESPONSE_SIM_PHONEBOOK_RECORDS_RECEIVED,
-                    "status = " + status +
-                    " received " + records.size() + " records");
+                    "status = " + status + " received " + records.size() + " records");
         }
 
         mRil.mSimPhonebookRecordsReceivedRegistrants.notifyRegistrants(
@@ -1108,7 +1106,7 @@
             @NetworkRegistrationInfo.Domain int domain,
             int causeCode, int additionalCauseCode) {
         mRil.processIndication(indicationType);
-        CellIdentity ci = CellIdentity.create(cellIdentity);
+        CellIdentity ci = RILUtils.convertHalCellIdentity(cellIdentity);
         if (ci == null
                 || TextUtils.isEmpty(chosenPlmn)
                 || (domain & NetworkRegistrationInfo.DOMAIN_CS_PS) == 0
@@ -1124,11 +1122,8 @@
         }
 
         mRil.mRegistrationFailedRegistrant.notifyRegistrant(
-                new AsyncResult(
-                        null,
-                        new RegistrationFailedEvent(ci, chosenPlmn, domain,
-                                causeCode, additionalCauseCode),
-                        null));
+                new AsyncResult(null, new RegistrationFailedEvent(ci, chosenPlmn, domain,
+                        causeCode, additionalCauseCode), null));
     }
 
     /**
@@ -1152,8 +1147,8 @@
             return;
         }
 
-        CellIdentity ci = CellIdentity.create(cellIdentity);
-        BarringInfo cbi = BarringInfo.create(cellIdentity, barringInfos);
+        BarringInfo cbi = new BarringInfo(RILUtils.convertHalCellIdentity(cellIdentity),
+                RILUtils.convertHalBarringInfoList(barringInfos));
 
         mRil.mBarringInfoChangedRegistrants.notifyRegistrants(
                 new AsyncResult(null, cbi, null));
@@ -1180,35 +1175,6 @@
         }
     }
 
-    /**
-     * Set the band from the physical channel config.
-     *
-     * @param builder the builder of {@link PhysicalChannelConfig}.
-     * @param config physical channel config from ril.
-     */
-    public void setBandToBuilder(PhysicalChannelConfig.Builder builder,
-            android.hardware.radio.V1_6.PhysicalChannelConfig config) {
-
-        android.hardware.radio.V1_6.PhysicalChannelConfig.Band band = config.band;
-
-        switch (band.getDiscriminator()) {
-            case Band.hidl_discriminator.geranBand:
-                builder.setBand(band.geranBand());
-                break;
-            case Band.hidl_discriminator.utranBand:
-                builder.setBand(band.utranBand());
-                break;
-            case Band.hidl_discriminator.eutranBand:
-                builder.setBand(band.eutranBand());
-                break;
-            case Band.hidl_discriminator.ngranBand:
-                builder.setBand(band.ngranBand());
-                break;
-            default:
-                mRil.riljLoge("Unsupported band type " + band.getDiscriminator());
-        }
-    }
-
     private void physicalChannelConfigsIndication(List<? extends Object> configs) {
         List<PhysicalChannelConfig> response = new ArrayList<>(configs.size());
         try {
@@ -1239,7 +1205,22 @@
                     android.hardware.radio.V1_6.PhysicalChannelConfig config =
                             (android.hardware.radio.V1_6.PhysicalChannelConfig) obj;
                     PhysicalChannelConfig.Builder builder = new PhysicalChannelConfig.Builder();
-                    setBandToBuilder(builder, config);
+                    switch (config.band.getDiscriminator()) {
+                        case Band.hidl_discriminator.geranBand:
+                            builder.setBand(config.band.geranBand());
+                            break;
+                        case Band.hidl_discriminator.utranBand:
+                            builder.setBand(config.band.utranBand());
+                            break;
+                        case Band.hidl_discriminator.eutranBand:
+                            builder.setBand(config.band.eutranBand());
+                            break;
+                        case Band.hidl_discriminator.ngranBand:
+                            builder.setBand(config.band.ngranBand());
+                            break;
+                        default:
+                            mRil.riljLoge("Unsupported band " + config.band.getDiscriminator());
+                    }
                     response.add(builder.setCellConnectionStatus(
                             RILUtils.convertHalCellConnectionStatus(config.status))
                             .setDownlinkChannelNumber(config.downlinkChannelNumber)
diff --git a/src/java/com/android/internal/telephony/RadioResponse.java b/src/java/com/android/internal/telephony/RadioResponse.java
index df39f4d..4e7f589 100644
--- a/src/java/com/android/internal/telephony/RadioResponse.java
+++ b/src/java/com/android/internal/telephony/RadioResponse.java
@@ -68,19 +68,6 @@
 import java.util.UUID;
 
 public class RadioResponse extends IRadioResponse.Stub {
-    // The number of the required config values for broadcast SMS stored in the C struct
-    // RIL_CDMA_BroadcastServiceInfo
-    private static final int CDMA_BSI_NO_OF_INTS_STRUCT = 3;
-
-    private static final int CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES = 31;
-
-    private static final String RADIO_POWER_FAILURE_BUGREPORT_UUID =
-            "316f3801-fa21-4954-a42f-0041eada3b31";
-    private static final String RADIO_POWER_FAILURE_RF_HARDWARE_ISSUE_UUID =
-            "316f3801-fa21-4954-a42f-0041eada3b32";
-    private static final String RADIO_POWER_FAILURE_NO_RF_CALIBRATION_UUID =
-            "316f3801-fa21-4954-a42f-0041eada3b33";
-
     RIL mRil;
 
     public RadioResponse(RIL ril) {
@@ -556,8 +543,7 @@
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param sms Response to sms sent as defined by SendSmsResult in types.hal
      */
-    public void sendSmsResponse(RadioResponseInfo responseInfo,
-            SendSmsResult sms) {
+    public void sendSmsResponse(RadioResponseInfo responseInfo, SendSmsResult sms) {
         responseSms(responseInfo, sms);
     }
 
@@ -757,7 +743,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param response 0 is the TS 27.007 service class bit vector of
      *        services for which the specified barring facility
@@ -768,7 +753,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param retry 0 is the number of retries remaining, or -1 if unknown
      */
@@ -784,7 +768,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param selection false for automatic selection, true for manual selection
      */
@@ -814,7 +797,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param networkInfos List of network operator information as OperatorInfos defined in
      *                     types.hal
@@ -852,7 +834,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      */
     public void stopNetworkScanResponse(RadioResponseInfo responseInfo) {
@@ -874,7 +855,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param version string containing version string for log reporting
      */
@@ -897,7 +877,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param enable true for "mute enabled" and false for "mute disabled"
      */
@@ -906,7 +885,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param status indicates CLIP status
      */
@@ -977,7 +955,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param bandModes List of RadioBandMode listing supported modes
      */
@@ -987,7 +964,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param commandResponse SAT/USAT response in hexadecimal format
      *        string starting with first byte of response
@@ -1033,7 +1009,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param nwType RadioPreferredNetworkType defined in types.hal
      */
@@ -1057,7 +1032,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param cells Vector of neighboring radio cell information
      */
@@ -1088,7 +1062,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param type CdmaRoamingType defined in types.hal
      */
@@ -1104,7 +1077,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param mode TTY mode
      */
@@ -1120,13 +1092,11 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param enable false for Standard Privacy Mode (Public Long Code Mask)
      *        true for Enhanced Privacy Mode (Private Long Code Mask)
      */
-    public void getPreferredVoicePrivacyResponse(RadioResponseInfo responseInfo,
-            boolean enable) {
+    public void getPreferredVoicePrivacyResponse(RadioResponseInfo responseInfo, boolean enable) {
         responseInts(responseInfo, enable ? 1 : 0);
     }
 
@@ -1145,7 +1115,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param sms Sms result struct as defined by SendSmsResult in types.hal
      */
@@ -1154,7 +1123,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error which
      *                     is defined in 1.6/types.hal
      * @param sms Sms result struct as defined by SendSmsResult in types.hal
@@ -1174,7 +1142,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error which
      *                     is defined in 1.6/types.hal
      * @param sms Sms result struct as defined by SendSmsResult in types.hal
@@ -1200,7 +1167,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param configs Vector of GSM/WCDMA Cell broadcast configs
      */
@@ -1224,7 +1190,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param configs Vector of CDMA Broadcast SMS configs.
      */
@@ -1248,7 +1213,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param mdn MDN if CDMA subscription is available
      * @param hSid is a comma separated list of H_SID (Home SID) if
@@ -1264,7 +1228,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param index record index where the cmda sms message is stored
      */
@@ -1328,7 +1291,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param source CDMA subscription source
      */
@@ -1354,7 +1316,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param iccIo IccIoResult as defined in types.hal corresponding to ICC IO response
      */
@@ -1364,7 +1325,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param rat Current voice RAT
      */
@@ -1381,8 +1341,7 @@
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param cellInfo List of current cell information known to radio
      */
-    public void getCellInfoListResponse_1_2(
-            RadioResponseInfo responseInfo,
+    public void getCellInfoListResponse_1_2(RadioResponseInfo responseInfo,
             ArrayList<android.hardware.radio.V1_2.CellInfo> cellInfo) {
         responseCellInfoList(responseInfo, cellInfo);
     }
@@ -1391,8 +1350,7 @@
      * @param responseInfo Response info struct containing response type, serial no. and error.
      * @param cellInfo List of current cell information known to radio.
      */
-    public void getCellInfoListResponse_1_4(
-            RadioResponseInfo responseInfo,
+    public void getCellInfoListResponse_1_4(RadioResponseInfo responseInfo,
             ArrayList<android.hardware.radio.V1_4.CellInfo> cellInfo) {
         responseCellInfoList(responseInfo, cellInfo);
     }
@@ -1401,8 +1359,7 @@
      * @param responseInfo Response info struct containing response type, serial no. and error.
      * @param cellInfo List of current cell information known to radio.
      */
-    public void getCellInfoListResponse_1_5(
-            RadioResponseInfo responseInfo,
+    public void getCellInfoListResponse_1_5(RadioResponseInfo responseInfo,
             ArrayList<android.hardware.radio.V1_5.CellInfo> cellInfo) {
         responseCellInfoList(responseInfo, cellInfo);
     }
@@ -1439,7 +1396,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param isRegistered false = not registered, true = registered
      * @param ratFamily RadioTechnologyFamily as defined in types.hal. This value is valid only if
@@ -1447,16 +1403,12 @@
      */
     public void getImsRegistrationStateResponse(RadioResponseInfo responseInfo,
             boolean isRegistered, int ratFamily) {
-        responseInts(
-                responseInfo,
-                isRegistered ? 1 : 0,
-                ratFamily == RadioTechnologyFamily.THREE_GPP
-                        ? PhoneConstants.PHONE_TYPE_GSM
+        responseInts(responseInfo, isRegistered ? 1 : 0,
+                ratFamily == RadioTechnologyFamily.THREE_GPP ? PhoneConstants.PHONE_TYPE_GSM
                         : PhoneConstants.PHONE_TYPE_CDMA);
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param sms Response to sms sent as defined by SendSmsResult in types.hal
      */
@@ -1465,18 +1417,15 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param result IccIoResult as defined in types.hal
      */
     public void iccTransmitApduBasicChannelResponse(RadioResponseInfo responseInfo,
-            android.hardware.radio.V1_0.IccIoResult
-                    result) {
+            android.hardware.radio.V1_0.IccIoResult result) {
         responseIccIo(responseInfo, result);
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param channelId session id of the logical channel.
      * @param selectResponse Contains the select response for the open channel command with one
@@ -1500,7 +1449,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param result IccIoResult as defined in types.hal
      */
@@ -1511,7 +1459,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param result string containing the contents of the NV item
      */
@@ -1561,21 +1508,16 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param result IccIoResult as defined in types.hal
      */
     public void requestIccSimAuthenticationResponse(RadioResponseInfo responseInfo,
-            android.hardware.radio.V1_0.IccIoResult
-                    result) {
+            android.hardware.radio.V1_0.IccIoResult result) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
-            IccIoResult ret = new IccIoResult(
-                    result.sw1,
-                    result.sw2,
-                    TextUtils.isEmpty(result.simResponse)
-                            ? null : result.simResponse.getBytes());
+            IccIoResult ret = new IccIoResult(result.sw1, result.sw2,
+                    TextUtils.isEmpty(result.simResponse) ? null : result.simResponse.getBytes());
             if (responseInfo.error == RadioError.NONE) {
                 sendMessageResponse(rr.mResult, ret);
             }
@@ -1630,7 +1572,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param statusInfo LceStatusInfo indicating LCE status
      */
@@ -1639,7 +1580,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param statusInfo LceStatusInfo indicating LCE status
      */
@@ -1652,7 +1592,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param activityInfo modem activity information
      */
@@ -1662,7 +1601,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param isEnabled Indicates whether NR dual connectivity is enabled or not, True if enabled
      *               else false.
@@ -1681,7 +1619,6 @@
     }
 
     /**
-     *
      * @param info Response info struct containing response type, serial no. and error
      */
     public void setNrDualConnectivityStateResponse(
@@ -1690,7 +1627,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param numAllowed number of allowed carriers which have been set correctly.
      *        On success, it must match the length of list Carriers->allowedCarriers.
@@ -1720,7 +1656,6 @@
     }
 
     /**
-     *
      * @param responseInfo Response info struct containing response type, serial no. and error
      */
     public void setAllowedCarriersResponse_1_4(RadioResponseInfo responseInfo) {
@@ -1911,7 +1846,7 @@
     public void getSimPhonebookCapacityResponse(
             android.hardware.radio.V1_6.RadioResponseInfo responseInfo,
             android.hardware.radio.V1_6.PhonebookCapacity pbCapacity) {
-        AdnCapacity capacity = new AdnCapacity(pbCapacity);
+        AdnCapacity capacity = RILUtils.convertHalPhonebookCapacity(pbCapacity);
         responseAdnCapacity(responseInfo, capacity);
     }
 
@@ -2023,6 +1958,21 @@
         responseIntArrayList_1_6(responseInfo, ints);
     }
 
+    /**
+     * Send int array response
+     * @param ril RIL to send response
+     * @param responseInfo responseInfo
+     * @param var response int array
+     */
+    public static void responseInts(RIL ril, android.hardware.radio.RadioResponseInfo responseInfo,
+            int ...var) {
+        final ArrayList<Integer> ints = new ArrayList<>();
+        for (int i = 0; i < var.length; i++) {
+            ints.add(var[i]);
+        }
+        responseIntArrayList(ril, responseInfo, ints);
+    }
+
     private void responseIntArrayList(RadioResponseInfo responseInfo, ArrayList<Integer> var) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
@@ -2054,6 +2004,28 @@
         }
     }
 
+    /**
+     * Send int array list response
+     * @param ril RIL to send response
+     * @param responseInfo responseInfo
+     * @param var response int array list
+     */
+    public static void responseIntArrayList(RIL ril,
+            android.hardware.radio.RadioResponseInfo responseInfo, ArrayList<Integer> var) {
+        RILRequest rr = ril.processResponse(responseInfo);
+
+        if (rr != null) {
+            int[] ret = new int[var.size()];
+            for (int i = 0; i < var.size(); i++) {
+                ret[i] = var.get(i);
+            }
+            if (responseInfo.error == RadioError.NONE) {
+                sendMessageResponse(rr.mResult, ret);
+            }
+            ril.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
     private void responseCurrentCalls(RadioResponseInfo responseInfo,
             ArrayList<android.hardware.radio.V1_0.Call> calls) {
         RILRequest rr = mRil.processResponse(responseInfo);
@@ -2199,6 +2171,24 @@
         }
     }
 
+    /**
+     * Send void response
+     * @param ril RIL to send response
+     * @param responseInfo response void
+     */
+    public static void responseVoid(RIL ril,
+            android.hardware.radio.RadioResponseInfo responseInfo) {
+        RILRequest rr = ril.processResponse(responseInfo);
+
+        if (rr != null) {
+            Object ret = null;
+            if (responseInfo.error == RadioError.NONE) {
+                sendMessageResponse(rr.mResult, ret);
+            }
+            ril.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
     private void responseString(RadioResponseInfo responseInfo, String str) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
@@ -2210,6 +2200,24 @@
         }
     }
 
+    /**
+     * Send string response
+     * @param ril RIL to send response
+     * @param responseInfo responseInfo
+     * @param str response string
+     */
+    public static void responseString(RIL ril,
+            android.hardware.radio.RadioResponseInfo responseInfo, String str) {
+        RILRequest rr = ril.processResponse(responseInfo);
+
+        if (rr != null) {
+            if (responseInfo.error == RadioError.NONE) {
+                sendMessageResponse(rr.mResult, str);
+            }
+            ril.processResponseDone(rr, responseInfo, str);
+        }
+    }
+
     private void responseStrings(RadioResponseInfo responseInfo, String ...str) {
         ArrayList<String> strings = new ArrayList<>();
         for (int i = 0; i < str.length; i++) {
@@ -2218,6 +2226,21 @@
         responseStringArrayList(mRil, responseInfo, strings);
     }
 
+    /**
+     * Send String array response
+     * @param ril RIL to send response
+     * @param responseInfo responseInfo
+     * @param str String array
+     */
+    public static void responseStrings(RIL ril,
+            android.hardware.radio.RadioResponseInfo responseInfo, String ...str) {
+        ArrayList<String> strings = new ArrayList<>();
+        for (int i = 0; i < str.length; i++) {
+            strings.add(str[i]);
+        }
+        responseStringArrayList(ril, responseInfo, strings);
+    }
+
     static void responseStringArrayList(RIL ril, RadioResponseInfo responseInfo,
             ArrayList<String> strings) {
         RILRequest rr = ril.processResponse(responseInfo);
@@ -2234,6 +2257,22 @@
         }
     }
 
+    private static void responseStringArrayList(RIL ril,
+            android.hardware.radio.RadioResponseInfo responseInfo, ArrayList<String> strings) {
+        RILRequest rr = ril.processResponse(responseInfo);
+
+        if (rr != null) {
+            String[] ret = new String[strings.size()];
+            for (int i = 0; i < strings.size(); i++) {
+                ret[i] = strings.get(i);
+            }
+            if (responseInfo.error == RadioError.NONE) {
+                sendMessageResponse(rr.mResult, ret);
+            }
+            ril.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
     private void responseLastCallFailCauseInfo(RadioResponseInfo responseInfo,
             LastCallFailCauseInfo fcInfo) {
         RILRequest rr = mRil.processResponse(responseInfo);
@@ -2255,7 +2294,7 @@
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
-            SignalStrength ret = new SignalStrength(signalStrength);
+            SignalStrength ret = RILUtils.convertHalSignalStrength(signalStrength);
             if (responseInfo.error == RadioError.NONE) {
                 sendMessageResponse(rr.mResult, ret);
             }
@@ -2269,7 +2308,7 @@
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
-            SignalStrength ret = new SignalStrength(signalStrength);
+            SignalStrength ret = RILUtils.convertHalSignalStrength(signalStrength);
             if (responseInfo.error == RadioError.NONE) {
                 sendMessageResponse(rr.mResult, ret);
             }
@@ -2283,7 +2322,7 @@
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
-            SignalStrength ret = new SignalStrength(signalStrength);
+            SignalStrength ret = RILUtils.convertHalSignalStrength(signalStrength);
             if (responseInfo.error == RadioError.NONE) {
                 sendMessageResponse(rr.mResult, ret);
             }
@@ -2297,7 +2336,7 @@
         RILRequest rr = mRil.processResponse_1_6(responseInfo);
 
         if (rr != null) {
-            SignalStrength ret = new SignalStrength(signalStrength);
+            SignalStrength ret = RILUtils.convertHalSignalStrength(signalStrength);
             if (responseInfo.error == RadioError.NONE) {
                 sendMessageResponse(rr.mResult, ret);
             }
@@ -2373,8 +2412,7 @@
     }
 
     private void responseCallForwardInfo(RadioResponseInfo responseInfo,
-            ArrayList<android.hardware.radio.V1_0.CallForwardInfo>
-                    callForwardInfos) {
+            ArrayList<android.hardware.radio.V1_0.CallForwardInfo> callForwardInfos) {
         RILRequest rr = mRil.processResponse(responseInfo);
         if (rr != null) {
             CallForwardInfo[] ret = new CallForwardInfo[callForwardInfos.size()];
@@ -2395,8 +2433,7 @@
     }
 
     private void responseOperatorInfos(RadioResponseInfo responseInfo,
-            ArrayList<android.hardware.radio.V1_0.OperatorInfo>
-                    networkInfos) {
+            ArrayList<android.hardware.radio.V1_0.OperatorInfo> networkInfos) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
@@ -2509,7 +2546,7 @@
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
-            ArrayList<SmsBroadcastConfigInfo> ret = new ArrayList<SmsBroadcastConfigInfo>();
+            ArrayList<SmsBroadcastConfigInfo> ret = new ArrayList<>();
             for (int i = 0; i < configs.size(); i++) {
                 ret.add(new SmsBroadcastConfigInfo(configs.get(i).fromServiceId,
                         configs.get(i).toServiceId, configs.get(i).fromCodeScheme,
@@ -2536,28 +2573,28 @@
                 // not be done by this transport layer. And needs to
                 // be done by the vendor ril or application logic.
                 int numInts;
-                numInts = CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES
-                        * CDMA_BSI_NO_OF_INTS_STRUCT + 1;
+                numInts = RILUtils.CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES
+                        * RILUtils.CDMA_BSI_NO_OF_INTS_STRUCT + 1;
                 ret = new int[numInts];
 
                 // Faking a default record for all possible records.
-                ret[0] = CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES;
+                ret[0] = RILUtils.CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES;
 
                 // Loop over CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES set 'english' as
                 // default language and selection status to false for all.
-                for (int i = 1; i < numInts; i += CDMA_BSI_NO_OF_INTS_STRUCT) {
-                    ret[i + 0] = i / CDMA_BSI_NO_OF_INTS_STRUCT;
+                for (int i = 1; i < numInts; i += RILUtils.CDMA_BSI_NO_OF_INTS_STRUCT) {
+                    ret[i + 0] = i / RILUtils.CDMA_BSI_NO_OF_INTS_STRUCT;
                     ret[i + 1] = 1;
                     ret[i + 2] = 0;
                 }
             } else {
                 int numInts;
-                numInts = (numServiceCategories * CDMA_BSI_NO_OF_INTS_STRUCT) + 1;
+                numInts = (numServiceCategories * RILUtils.CDMA_BSI_NO_OF_INTS_STRUCT) + 1;
                 ret = new int[numInts];
 
                 ret[0] = numServiceCategories;
                 for (int i = 1, j = 0; j < configs.size();
-                        j++, i = i + CDMA_BSI_NO_OF_INTS_STRUCT) {
+                        j++, i = i + RILUtils.CDMA_BSI_NO_OF_INTS_STRUCT) {
                     ret[i] = configs.get(j).serviceCategory;
                     ret[i + 1] = configs.get(j).language;
                     ret[i + 2] = configs.get(j).selected ? 1 : 0;
@@ -2623,8 +2660,7 @@
         }
     }
 
-    private void responseHardwareConfig(
-            RadioResponseInfo responseInfo,
+    private void responseHardwareConfig(RadioResponseInfo responseInfo,
             ArrayList<android.hardware.radio.V1_0.HardwareConfig> config) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
@@ -2677,8 +2713,7 @@
     }
 
     private void responseCarrierRestrictions(RadioResponseInfo responseInfo, boolean allAllowed,
-            CarrierRestrictionsWithPriority carriers,
-            int multiSimPolicy) {
+            CarrierRestrictionsWithPriority carriers, int multiSimPolicy) {
         RILRequest rr = mRil.processResponse(responseInfo);
         if (rr == null) {
             return;
@@ -2774,7 +2809,8 @@
         mRil.mLastRadioPowerResult = info.error;
         if (info.error != RadioError.RADIO_NOT_AVAILABLE && info.error != RadioError.NONE) {
             AnomalyReporter.reportAnomaly(
-                    UUID.fromString(RADIO_POWER_FAILURE_BUGREPORT_UUID), "Radio power failure");
+                    UUID.fromString(RILUtils.RADIO_POWER_FAILURE_BUGREPORT_UUID),
+                    "Radio power failure");
         }
     }
 
@@ -2786,15 +2822,17 @@
         mRil.mLastRadioPowerResult = info.error;
         if (info.error == android.hardware.radio.V1_6.RadioError.RF_HARDWARE_ISSUE) {
             AnomalyReporter.reportAnomaly(
-                    UUID.fromString(RADIO_POWER_FAILURE_RF_HARDWARE_ISSUE_UUID), "RF HW damaged");
+                    UUID.fromString(RILUtils.RADIO_POWER_FAILURE_RF_HARDWARE_ISSUE_UUID),
+                    "RF HW damaged");
         } else if (info.error == android.hardware.radio.V1_6.RadioError.NO_RF_CALIBRATION_INFO) {
             AnomalyReporter.reportAnomaly(
-                    UUID.fromString(RADIO_POWER_FAILURE_NO_RF_CALIBRATION_UUID),
+                    UUID.fromString(RILUtils.RADIO_POWER_FAILURE_NO_RF_CALIBRATION_UUID),
                     "No RF calibration data");
         } else if (info.error != android.hardware.radio.V1_6.RadioError.RADIO_NOT_AVAILABLE
                 && info.error != android.hardware.radio.V1_6.RadioError.NONE) {
             AnomalyReporter.reportAnomaly(
-                    UUID.fromString(RADIO_POWER_FAILURE_BUGREPORT_UUID), "Radio power failure");
+                    UUID.fromString(RILUtils.RADIO_POWER_FAILURE_BUGREPORT_UUID),
+                    "Radio power failure");
         }
     }
 
@@ -2818,7 +2856,7 @@
         if (rr != null) {
             ArrayList<RadioAccessSpecifier> specifiers = new ArrayList<>();
             for (android.hardware.radio.V1_5.RadioAccessSpecifier specifier : halSpecifiers) {
-                specifiers.add(convertRadioAccessSpecifier(specifier));
+                specifiers.add(RILUtils.convertHalRadioAccessSpecifier(specifier));
             }
             mRil.riljLog("getSystemSelectionChannelsResponse: from HIDL: " + specifiers);
             if (info.error == RadioError.NONE) {
@@ -2828,34 +2866,6 @@
         }
     }
 
-    private static RadioAccessSpecifier convertRadioAccessSpecifier(
-            android.hardware.radio.V1_5.RadioAccessSpecifier specifier) {
-        if (specifier == null) return null;
-        ArrayList<Integer> halBands = new ArrayList<>();
-        switch (specifier.bands.getDiscriminator()) {
-            case android.hardware.radio.V1_5.RadioAccessSpecifier.Bands.hidl_discriminator
-                    .geranBands:
-                halBands = specifier.bands.geranBands();
-                break;
-            case android.hardware.radio.V1_5.RadioAccessSpecifier.Bands.hidl_discriminator
-                    .utranBands:
-                halBands = specifier.bands.utranBands();
-                break;
-            case android.hardware.radio.V1_5.RadioAccessSpecifier.Bands.hidl_discriminator
-                    .eutranBands:
-                halBands = specifier.bands.eutranBands();
-                break;
-            case android.hardware.radio.V1_5.RadioAccessSpecifier.Bands.hidl_discriminator
-                    .ngranBands:
-                halBands = specifier.bands.ngranBands();
-                break;
-        }
-        return new RadioAccessSpecifier(
-                RILUtils.convertHalRadioAccessNetworks(specifier.radioAccessNetwork),
-                halBands.stream().mapToInt(Integer::intValue).toArray(),
-                specifier.channels.stream().mapToInt(Integer::intValue).toArray());
-    }
-
     /**
      * @param responseInfo Response info struct containing response type, serial no. and error.
      * @param cellIdentity CellIdentity for the barringInfos.
@@ -2867,7 +2877,8 @@
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
-            BarringInfo bi = BarringInfo.create(cellIdentity, barringInfos);
+            BarringInfo bi = new BarringInfo(RILUtils.convertHalCellIdentity(cellIdentity),
+                    RILUtils.convertHalBarringInfoList(barringInfos));
             if (responseInfo.error == RadioError.NONE) {
                 sendMessageResponse(rr.mResult, bi);
                 // notify all registrants for the possible barring info change
diff --git a/src/java/com/android/internal/telephony/SimIndication.java b/src/java/com/android/internal/telephony/SimIndication.java
new file mode 100644
index 0000000..24e4d47
--- /dev/null
+++ b/src/java/com/android/internal/telephony/SimIndication.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2021 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;
+
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_SIM_PHONEBOOK_CHANGED;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_SIM_PHONEBOOK_RECORDS_RECEIVED;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SIM_REFRESH;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_STK_EVENT_NOTIFY;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_STK_PROACTIVE_COMMAND;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_STK_SESSION_END;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_UICC_APPLICATIONS_ENABLEMENT_CHANGED;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED;
+
+import android.hardware.radio.sim.IRadioSimIndication;
+import android.os.AsyncResult;
+
+import com.android.internal.telephony.uicc.IccRefreshResponse;
+import com.android.internal.telephony.uicc.ReceivedPhonebookRecords;
+import com.android.internal.telephony.uicc.SimPhonebookRecord;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Interface declaring unsolicited radio indications for SIM APIs.
+ */
+public class SimIndication extends IRadioSimIndication.Stub {
+    private final RIL mRil;
+
+    public SimIndication(RIL ril) {
+        mRil = ril;
+    }
+
+    /**
+     * Indicates when the carrier info to encrypt IMSI is being requested.
+     * @param indicationType Type of radio indication
+     */
+    public void carrierInfoForImsiEncryption(int indicationType) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION, null);
+
+        mRil.mCarrierInfoForImsiEncryptionRegistrants.notifyRegistrants(
+                new AsyncResult(null, null, null));
+    }
+
+    /**
+     * Indicates when CDMA subscription source changed.
+     * @param indicationType Type of radio indication
+     * @param cdmaSource New CdmaSubscriptionSource
+     */
+    public void cdmaSubscriptionSourceChanged(int indicationType, int cdmaSource) {
+        mRil.processIndication(indicationType);
+
+        int[] response = new int[]{cdmaSource};
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, response);
+
+        mRil.mCdmaSubscriptionChangedRegistrants.notifyRegistrants(
+                new AsyncResult(null, response, null));
+    }
+
+    /**
+     * Indicates when the phonebook is changed.
+     * @param indicationType Type of radio indication
+     */
+    public void simPhonebookChanged(int indicationType) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) {
+            mRil.unsljLog(RIL_UNSOL_RESPONSE_SIM_PHONEBOOK_CHANGED);
+        }
+
+        mRil.mSimPhonebookChangedRegistrants.notifyRegistrants();
+    }
+
+    /**
+     * Indicates the content of all the used records in the SIM phonebook.
+     * @param indicationType Type of radio indication
+     * @param status Status of PbReceivedStatus
+     * @param records Content of the SIM phonebook records
+     */
+    public void simPhonebookRecordsReceived(int indicationType, byte status,
+            android.hardware.radio.sim.PhonebookRecordInfo[] records) {
+        mRil.processIndication(indicationType);
+
+        List<SimPhonebookRecord> simPhonebookRecords = new ArrayList<>();
+
+        for (android.hardware.radio.sim.PhonebookRecordInfo record : records) {
+            simPhonebookRecords.add(RILUtils.convertHalPhonebookRecordInfo(record));
+        }
+
+        if (RIL.RILJ_LOGD) {
+            mRil.unsljLogRet(RIL_UNSOL_RESPONSE_SIM_PHONEBOOK_RECORDS_RECEIVED,
+                    "status = " + status + " received " + records.length + " records");
+        }
+
+        mRil.mSimPhonebookRecordsReceivedRegistrants.notifyRegistrants(new AsyncResult(
+                null, new ReceivedPhonebookRecords(status, simPhonebookRecords), null));
+    }
+
+    /**
+     * Indicates that file(s) on the SIM have been updated, or the SIM has been reinitialized.
+     * @param indicationType Type of radio indication
+     * @param refreshResult Result of SIM refresh
+     */
+    public void simRefresh(int indicationType,
+            android.hardware.radio.sim.SimRefreshResult refreshResult) {
+        mRil.processIndication(indicationType);
+
+        IccRefreshResponse response = new IccRefreshResponse();
+        response.refreshResult = refreshResult.type;
+        response.efId = refreshResult.efId;
+        response.aid = refreshResult.aid;
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_SIM_REFRESH, response);
+
+        mRil.mIccRefreshRegistrants.notifyRegistrants(new AsyncResult(null, response, null));
+    }
+
+    /**
+     * Indicates that SIM state changed.
+     * @param indicationType Type of radio indication
+     */
+    public void simStatusChanged(int indicationType) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED);
+
+        mRil.mIccStatusChangedRegistrants.notifyRegistrants();
+    }
+
+    /**
+     * Indicates when SIM notifies applications some event happens.
+     * @param indicationType Type of radio indication
+     * @param cmd SAT/USAT commands or responses sent by ME to SIM or commands handled by ME,
+     *        represented as byte array starting with first byte of response data for command tag.
+     *        Refer to TS 102.223 section 9.4 for command types
+     */
+    public void stkEventNotify(int indicationType, String cmd) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_STK_EVENT_NOTIFY);
+
+        if (mRil.mCatEventRegistrant != null) {
+            mRil.mCatEventRegistrant.notifyRegistrant(new AsyncResult(null, cmd, null));
+        }
+    }
+
+    /**
+     * Indicates when SIM issue a STK proactive command to applications.
+     * @param indicationType Type of radio indication
+     * @param cmd SAT/USAT proactive represented as byte array starting with command tag.
+     *        Refer to TS 102.223 section 9.4 for command types
+     */
+    public void stkProactiveCommand(int indicationType, String cmd) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_STK_PROACTIVE_COMMAND);
+
+        if (mRil.mCatProCmdRegistrant != null) {
+            mRil.mCatProCmdRegistrant.notifyRegistrant(new AsyncResult(null, cmd, null));
+        }
+    }
+
+    /**
+     * Indicates when STK session is terminated by SIM.
+     * @param indicationType Type of radio indication
+     */
+    public void stkSessionEnd(int indicationType) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_STK_SESSION_END);
+
+        if (mRil.mCatSessionEndRegistrant != null) {
+            mRil.mCatSessionEndRegistrant.notifyRegistrant(new AsyncResult(null, null, null));
+        }
+    }
+
+    /**
+     * Indicated when there is a change in subscription status.
+     * @param indicationType Type of radio indication
+     * @param activate false for subscription deactivated, true for subscription activated
+     */
+    public void subscriptionStatusChanged(int indicationType, boolean activate) {
+        mRil.processIndication(indicationType);
+
+        int[] response = new int[]{activate ? 1 : 0};
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED, response);
+
+        mRil.mSubscriptionStatusRegistrants.notifyRegistrants(
+                new AsyncResult(null, response, null));
+    }
+
+    /**
+     * Report change of whether uiccApplications are enabled or disabled.
+     * @param indicationType Type of radio indication
+     * @param enabled Whether uiccApplications are enabled or disabled
+     */
+    public void uiccApplicationsEnablementChanged(int indicationType, boolean enabled) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) {
+            mRil.unsljLogRet(RIL_UNSOL_UICC_APPLICATIONS_ENABLEMENT_CHANGED, enabled);
+        }
+
+        mRil.mUiccApplicationsEnablementRegistrants.notifyResult(enabled);
+    }
+}
diff --git a/src/java/com/android/internal/telephony/SimResponse.java b/src/java/com/android/internal/telephony/SimResponse.java
new file mode 100644
index 0000000..a365b07
--- /dev/null
+++ b/src/java/com/android/internal/telephony/SimResponse.java
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2021 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;
+
+import android.hardware.radio.RadioError;
+import android.hardware.radio.RadioResponseInfo;
+import android.hardware.radio.sim.IRadioSimResponse;
+import android.telephony.CarrierRestrictionRules;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+
+import com.android.internal.telephony.uicc.AdnCapacity;
+import com.android.internal.telephony.uicc.IccCardStatus;
+import com.android.internal.telephony.uicc.IccIoResult;
+
+import java.util.ArrayList;
+
+/**
+ * Interface declaring response functions to solicited radio requests for SIM APIs.
+ */
+public class SimResponse extends IRadioSimResponse.Stub {
+    private final RIL mRil;
+
+    public SimResponse(RIL ril) {
+        mRil = ril;
+    }
+
+    private void responseIccIo(RadioResponseInfo responseInfo,
+            android.hardware.radio.sim.IccIoResult result) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            IccIoResult ret = new IccIoResult(result.sw1, result.sw2, result.simResponse);
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, ret);
+            }
+            mRil.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
+    /**
+     * Acknowledge the receipt of radio request sent to the vendor. This must be sent only for
+     * radio request which take long time to respond.
+     * For more details, refer https://source.android.com/devices/tech/connect/ril.html
+     * @param serial Serial no. of the request whose acknowledgement is sent.
+     */
+    public void acknowledgeRequest(int serial) {
+        mRil.processRequestAck(serial);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error.
+     * @param enabled whether UICC applications are enabled.
+     */
+    public void areUiccApplicationsEnabledResponse(RadioResponseInfo responseInfo,
+            boolean enabled) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, enabled);
+            }
+            mRil.processResponseDone(rr, responseInfo, enabled);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param remainingAttempts Number of retries remaining, must be equal to -1 if unknown.
+     */
+    public void changeIccPin2ForAppResponse(RadioResponseInfo responseInfo, int remainingAttempts) {
+        RadioResponse.responseInts(mRil, responseInfo, remainingAttempts);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param remainingAttempts Number of retries remaining, must be equal to -1 if unknown.
+     */
+    public void changeIccPinForAppResponse(RadioResponseInfo responseInfo, int remainingAttempts) {
+        RadioResponse.responseInts(mRil, responseInfo, remainingAttempts);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error.
+     */
+    public void enableUiccApplicationsResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param carrierRestrictions Carrier restriction information.
+     * @param multiSimPolicy Policy for multi-sim devices.
+     */
+    public void getAllowedCarriersResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.sim.CarrierRestrictions carrierRestrictions,
+            int multiSimPolicy) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+        if (rr == null) {
+            return;
+        }
+        CarrierRestrictionRules ret;
+        int policy = CarrierRestrictionRules.MULTISIM_POLICY_NONE;
+        if (multiSimPolicy
+                == android.hardware.radio.sim.SimLockMultiSimPolicy.ONE_VALID_SIM_MUST_BE_PRESENT) {
+            policy = CarrierRestrictionRules.MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT;
+        }
+
+        int carrierRestrictionDefault =
+                CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED;
+        if (carrierRestrictions.priority && !carrierRestrictions.allowedCarriersPrioritized) {
+            carrierRestrictionDefault = CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_ALLOWED;
+        }
+
+        ret = CarrierRestrictionRules.newBuilder()
+                .setAllowedCarriers(RILUtils.convertHalCarrierList(
+                        carrierRestrictions.allowedCarriers))
+                .setExcludedCarriers(RILUtils.convertHalCarrierList(
+                        carrierRestrictions.excludedCarriers))
+                .setDefaultCarrierRestriction(carrierRestrictionDefault)
+                .setMultiSimPolicy(policy)
+                .build();
+
+        if (responseInfo.error == RadioError.NONE) {
+            RadioResponse.sendMessageResponse(rr.mResult, ret);
+        }
+        mRil.processResponseDone(rr, responseInfo, ret);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param mdn MDN if CDMA subscription is available
+     * @param hSid is a comma separated list of H_SID (Home SID) if
+     *        CDMA subscription is available, in decimal format
+     * @param hNid is a comma separated list of H_NID (Home NID) if
+     *        CDMA subscription is available, in decimal format
+     * @param min MIN (10 digits, MIN2+MIN1) if CDMA subscription is available
+     * @param prl PRL version if CDMA subscription is available
+     */
+    public void getCdmaSubscriptionResponse(RadioResponseInfo responseInfo, String mdn,
+            String hSid, String hNid, String min, String prl) {
+        RadioResponse.responseStrings(mRil, responseInfo, mdn, hSid, hNid, min, prl);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param source CDMA subscription source
+     */
+    public void getCdmaSubscriptionSourceResponse(RadioResponseInfo responseInfo, int source) {
+        RadioResponse.responseInts(mRil, responseInfo, source);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param response 0 is the TS 27.007 service class bit vector of services for which the
+     *        specified barring facility is active. "0" means "disabled for all"
+     */
+    public void getFacilityLockForAppResponse(RadioResponseInfo responseInfo, int response) {
+        RadioResponse.responseInts(mRil, responseInfo, response);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param cardStatus ICC card status as defined by CardStatus
+     */
+    public void getIccCardStatusResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.sim.CardStatus cardStatus) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            IccCardStatus iccCardStatus = RILUtils.convertHalCardStatus(cardStatus);
+            mRil.riljLog("responseIccCardStatus: from HIDL: " + iccCardStatus);
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, iccCardStatus);
+            }
+            mRil.processResponseDone(rr, responseInfo, iccCardStatus);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param imsi String containing the IMSI
+     */
+    public void getImsiForAppResponse(RadioResponseInfo responseInfo, String imsi) {
+        RadioResponse.responseString(mRil, responseInfo, imsi);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error.
+     * @param pbCapacity Contains the adn, email, anr capacities in the sim card.
+     */
+    public void getSimPhonebookCapacityResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.sim.PhonebookCapacity pbCapacity) {
+        AdnCapacity capacity = RILUtils.convertHalPhonebookCapacity(pbCapacity);
+        RILRequest rr = mRil.processResponse(responseInfo);
+        if (rr != null) {
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, capacity);
+            }
+            mRil.processResponseDone(rr, responseInfo, capacity);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error.
+     */
+    public void getSimPhonebookRecordsResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void iccCloseLogicalChannelResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param iccIo ICC IO operation response as defined by IccIoResult
+     */
+    public void iccIoForAppResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.sim.IccIoResult iccIo) {
+        responseIccIo(responseInfo, iccIo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param channelId session id of the logical channel.
+     * @param selectResponse Contains the select response for the open channel command with one
+     *        byte per integer
+     */
+    public void iccOpenLogicalChannelResponse(RadioResponseInfo responseInfo, int channelId,
+            byte[] selectResponse) {
+        ArrayList<Integer> arr = new ArrayList<>();
+        arr.add(channelId);
+        for (int i = 0; i < selectResponse.length; i++) {
+            arr.add((int) selectResponse[i]);
+        }
+        RadioResponse.responseIntArrayList(mRil, responseInfo, arr);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param iccIo ICC IO operation response as defined by IccIoResult
+     */
+    public void iccTransmitApduBasicChannelResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.sim.IccIoResult iccIo) {
+        responseIccIo(responseInfo, iccIo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param iccIo ICC IO operation response as defined by IccIoResult
+     */
+    public void iccTransmitApduLogicalChannelResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.sim.IccIoResult iccIo) {
+        responseIccIo(responseInfo, iccIo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void reportStkServiceIsRunningResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param iccIo ICC IO operation response as defined by IccIoResult
+     */
+    public void requestIccSimAuthenticationResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.sim.IccIoResult iccIo) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            IccIoResult ret = new IccIoResult(iccIo.sw1, iccIo.sw2,
+                    TextUtils.isEmpty(iccIo.simResponse) ? null : iccIo.simResponse);
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, ret);
+            }
+            mRil.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
+    /**
+     * This method is deprecated and should not be used.
+     *
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param response response string of the challenge/response algo for ISIM auth in base64 format
+     */
+    public void requestIsimAuthenticationResponse(RadioResponseInfo responseInfo, String response) {
+        // TODO (b/199433581): remove this method
+        throw new RuntimeException("Inexplicable response received for requestIsimAuthentication");
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param commandResponse SAT/USAT response in hexadecimal format
+     *        string starting with first byte of response
+     */
+    public void sendEnvelopeResponse(RadioResponseInfo responseInfo, String commandResponse) {
+        RadioResponse.responseString(mRil, responseInfo, commandResponse);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param iccIo ICC IO operation response as defined by IccIoResult
+     */
+    public void sendEnvelopeWithStatusResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.sim.IccIoResult iccIo) {
+        responseIccIo(responseInfo, iccIo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void sendTerminalResponseToSimResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setAllowedCarriersResponse(RadioResponseInfo responseInfo) {
+        int ret = TelephonyManager.SET_CARRIER_RESTRICTION_ERROR;
+        RILRequest rr = mRil.processResponse(responseInfo);
+        if (rr != null) {
+            mRil.riljLog("setAllowedCarriersResponse - error = " + responseInfo.error);
+
+            if (responseInfo.error == RadioError.NONE) {
+                ret = TelephonyManager.SET_CARRIER_RESTRICTION_SUCCESS;
+                RadioResponse.sendMessageResponse(rr.mResult, ret);
+            }
+            mRil.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setCarrierInfoForImsiEncryptionResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setCdmaSubscriptionSourceResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param retry 0 is the number of retries remaining, or -1 if unknown
+     */
+    public void setFacilityLockForAppResponse(RadioResponseInfo responseInfo, int retry) {
+        RadioResponse.responseInts(mRil, responseInfo, retry);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setSimCardPowerResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setUiccSubscriptionResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param remainingAttempts Number of retries remaining, must be equal to -1 if unknown.
+     */
+    public void supplyIccPin2ForAppResponse(RadioResponseInfo responseInfo, int remainingAttempts) {
+        RadioResponse.responseInts(mRil, responseInfo, remainingAttempts);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param remainingAttempts Number of retries remaining, must be equal to -1 if unknown.
+     */
+    public void supplyIccPinForAppResponse(RadioResponseInfo responseInfo, int remainingAttempts) {
+        RadioResponse.responseInts(mRil, responseInfo, remainingAttempts);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param remainingAttempts Number of retries remaining, must be equal to -1 if unknown.
+     */
+    public void supplyIccPuk2ForAppResponse(RadioResponseInfo responseInfo, int remainingAttempts) {
+        RadioResponse.responseInts(mRil, responseInfo, remainingAttempts);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param remainingAttempts Number of retries remaining, must be equal to -1 if unknown.
+     */
+    public void supplyIccPukForAppResponse(RadioResponseInfo responseInfo, int remainingAttempts) {
+        RadioResponse.responseInts(mRil, responseInfo, remainingAttempts);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param persoType SIM Personalisation type
+     * @param remainingRetries postiive values indicates number of retries remaining,
+     * must be equal to -1 if number of retries is infinite.
+     */
+    public void supplySimDepersonalizationResponse(RadioResponseInfo responseInfo, int persoType,
+            int remainingRetries) {
+        RadioResponse.responseInts(mRil, responseInfo, persoType, remainingRetries);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error.
+     * @param updatedRecordIndex The index of the updated record.
+     */
+    public void updateSimPhonebookRecordsResponse(RadioResponseInfo responseInfo,
+            int updatedRecordIndex) {
+        RadioResponse.responseInts(mRil, responseInfo, updatedRecordIndex);
+    }
+}
diff --git a/src/java/com/android/internal/telephony/VoiceIndication.java b/src/java/com/android/internal/telephony/VoiceIndication.java
new file mode 100644
index 0000000..da2c33b
--- /dev/null
+++ b/src/java/com/android/internal/telephony/VoiceIndication.java
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2021 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;
+
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CALL_RING;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CDMA_CALL_WAITING;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CDMA_INFO_REC;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CDMA_OTA_PROVISION_STATUS;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_EMERGENCY_NUMBER_LIST;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_SS;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESEND_INCALL_MUTE;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RINGBACK_TONE;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SRVCC_STATE_NOTIFY;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_STK_CALL_SETUP;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_STK_CC_ALPHA_NOTIFY;
+
+import android.hardware.radio.voice.IRadioVoiceIndication;
+import android.os.AsyncResult;
+import android.telephony.emergency.EmergencyNumber;
+
+import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
+import com.android.internal.telephony.cdma.CdmaInformationRecords;
+import com.android.internal.telephony.gsm.SsData;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Interface declaring unsolicited radio indications for voice APIs.
+ */
+public class VoiceIndication extends IRadioVoiceIndication.Stub {
+    private final RIL mRil;
+
+    public VoiceIndication(RIL ril) {
+        mRil = ril;
+    }
+
+    /**
+     * Ring indication for an incoming call (eg, RING or CRING event).
+     * The rate of these events is controlled by ro.telephony.call_ring.delay and has a default
+     * value of 3000 (3 seconds) if absent.
+     * @param indicationType Type of radio indication
+     * @param isGsm true for GSM & false for CDMA
+     * @param record CDMA signal information record
+     */
+    public void callRing(int indicationType, boolean isGsm,
+            android.hardware.radio.voice.CdmaSignalInfoRecord record) {
+        mRil.processIndication(indicationType);
+
+        char[] response = null;
+
+        // Ignore record for gsm
+        if (!isGsm) {
+            // TODO: Clean this up with a parcelable class for better self-documentation
+            response = new char[4];
+            response[0] = (char) (record.isPresent ? 1 : 0);
+            response[1] = (char) record.signalType;
+            response[2] = (char) record.alertPitch;
+            response[3] = (char) record.signal;
+            mRil.writeMetricsCallRing(response);
+        }
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CALL_RING, response);
+
+        if (mRil.mRingRegistrant != null) {
+            mRil.mRingRegistrant.notifyRegistrant(new AsyncResult(null, response, null));
+        }
+    }
+
+    /**
+     * Indicates when call state has changed. Redundant or extraneous invocations are tolerated.
+     * @param indicationType Type of radio indication
+     */
+    public void callStateChanged(int indicationType) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED);
+
+        mRil.mCallStateRegistrants.notifyRegistrants();
+    }
+
+    /**
+     * Indicates when CDMA radio receives a call waiting indication.
+     * @param indicationType Type of radio indication
+     * @param callWaitingRecord Cdma CallWaiting information
+     */
+    public void cdmaCallWaiting(int indicationType,
+            android.hardware.radio.voice.CdmaCallWaiting callWaitingRecord) {
+        mRil.processIndication(indicationType);
+
+        // TODO: create a CdmaCallWaitingNotification constructor that takes in these fields to make
+        // sure no fields are missing
+        CdmaCallWaitingNotification notification = new CdmaCallWaitingNotification();
+        notification.number = callWaitingRecord.number;
+        notification.numberPresentation = CdmaCallWaitingNotification.presentationFromCLIP(
+                callWaitingRecord.numberPresentation);
+        notification.name = callWaitingRecord.name;
+        notification.namePresentation = notification.numberPresentation;
+        notification.isPresent = callWaitingRecord.signalInfoRecord.isPresent ? 1 : 0;
+        notification.signalType = callWaitingRecord.signalInfoRecord.signalType;
+        notification.alertPitch = callWaitingRecord.signalInfoRecord.alertPitch;
+        notification.signal = callWaitingRecord.signalInfoRecord.signal;
+        notification.numberType = callWaitingRecord.numberType;
+        notification.numberPlan = callWaitingRecord.numberPlan;
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CDMA_CALL_WAITING, notification);
+
+        mRil.mCallWaitingInfoRegistrants.notifyRegistrants(
+                new AsyncResult(null, notification, null));
+    }
+
+    /**
+     * Indicates when CDMA radio receives one or more info recs.
+     * @param indicationType Type of radio indication
+     * @param records New CDMA information
+     */
+    public void cdmaInfoRec(int indicationType,
+            android.hardware.radio.voice.CdmaInformationRecords records) {
+        mRil.processIndication(indicationType);
+
+        int numberOfInfoRecs = records.infoRec.length;
+        for (int i = 0; i < numberOfInfoRecs; i++) {
+            android.hardware.radio.voice.CdmaInformationRecord record = records.infoRec[i];
+            int id = record.name;
+            CdmaInformationRecords cdmaInformationRecords;
+            switch (id) {
+                case CdmaInformationRecords.RIL_CDMA_DISPLAY_INFO_REC:
+                case CdmaInformationRecords.RIL_CDMA_EXTENDED_DISPLAY_INFO_REC:
+                    CdmaInformationRecords.CdmaDisplayInfoRec cdmaDisplayInfoRec =
+                            new CdmaInformationRecords.CdmaDisplayInfoRec(id,
+                                    record.display[0].alphaBuf);
+                    cdmaInformationRecords = new CdmaInformationRecords(cdmaDisplayInfoRec);
+                    break;
+
+                case CdmaInformationRecords.RIL_CDMA_CALLED_PARTY_NUMBER_INFO_REC:
+                case CdmaInformationRecords.RIL_CDMA_CALLING_PARTY_NUMBER_INFO_REC:
+                case CdmaInformationRecords.RIL_CDMA_CONNECTED_NUMBER_INFO_REC:
+                    android.hardware.radio.voice.CdmaNumberInfoRecord numInfoRecord =
+                            record.number[0];
+                    CdmaInformationRecords.CdmaNumberInfoRec cdmaNumberInfoRec =
+                            new CdmaInformationRecords.CdmaNumberInfoRec(id, numInfoRecord.number,
+                                    numInfoRecord.numberType, numInfoRecord.numberPlan,
+                                    numInfoRecord.pi, numInfoRecord.si);
+                    cdmaInformationRecords = new CdmaInformationRecords(cdmaNumberInfoRec);
+                    break;
+
+                case CdmaInformationRecords.RIL_CDMA_SIGNAL_INFO_REC:
+                    android.hardware.radio.voice.CdmaSignalInfoRecord signalInfoRecord =
+                            record.signal[0];
+                    CdmaInformationRecords.CdmaSignalInfoRec cdmaSignalInfoRec =
+                            new CdmaInformationRecords.CdmaSignalInfoRec(
+                                    signalInfoRecord.isPresent ? 1 : 0, signalInfoRecord.signalType,
+                                    signalInfoRecord.alertPitch, signalInfoRecord.signal);
+                    cdmaInformationRecords = new CdmaInformationRecords(cdmaSignalInfoRec);
+                    break;
+
+                case CdmaInformationRecords.RIL_CDMA_REDIRECTING_NUMBER_INFO_REC:
+                    android.hardware.radio.voice.CdmaRedirectingNumberInfoRecord
+                            redirectingNumberInfoRecord = record.redir[0];
+                    CdmaInformationRecords.CdmaRedirectingNumberInfoRec
+                            cdmaRedirectingNumberInfoRec =
+                            new CdmaInformationRecords.CdmaRedirectingNumberInfoRec(
+                                    redirectingNumberInfoRecord.redirectingNumber.number,
+                                    redirectingNumberInfoRecord.redirectingNumber.numberType,
+                                    redirectingNumberInfoRecord.redirectingNumber.numberPlan,
+                                    redirectingNumberInfoRecord.redirectingNumber.pi,
+                                    redirectingNumberInfoRecord.redirectingNumber.si,
+                                    redirectingNumberInfoRecord.redirectingReason);
+                    cdmaInformationRecords = new CdmaInformationRecords(
+                            cdmaRedirectingNumberInfoRec);
+                    break;
+
+                case CdmaInformationRecords.RIL_CDMA_LINE_CONTROL_INFO_REC:
+                    android.hardware.radio.voice.CdmaLineControlInfoRecord lineControlInfoRecord =
+                            record.lineCtrl[0];
+                    CdmaInformationRecords.CdmaLineControlInfoRec cdmaLineControlInfoRec =
+                            new CdmaInformationRecords.CdmaLineControlInfoRec(
+                                    lineControlInfoRecord.lineCtrlPolarityIncluded,
+                                    lineControlInfoRecord.lineCtrlToggle,
+                                    lineControlInfoRecord.lineCtrlReverse,
+                                    lineControlInfoRecord.lineCtrlPowerDenial);
+                    cdmaInformationRecords = new CdmaInformationRecords(cdmaLineControlInfoRec);
+                    break;
+
+                case CdmaInformationRecords.RIL_CDMA_T53_CLIR_INFO_REC:
+                    CdmaInformationRecords.CdmaT53ClirInfoRec cdmaT53ClirInfoRec =
+                            new CdmaInformationRecords.CdmaT53ClirInfoRec(record.clir[0].cause);
+                    cdmaInformationRecords = new CdmaInformationRecords(cdmaT53ClirInfoRec);
+                    break;
+
+                case CdmaInformationRecords.RIL_CDMA_T53_AUDIO_CONTROL_INFO_REC:
+                    android.hardware.radio.voice.CdmaT53AudioControlInfoRecord
+                            audioControlInfoRecord = record.audioCtrl[0];
+                    CdmaInformationRecords.CdmaT53AudioControlInfoRec cdmaT53AudioControlInfoRec =
+                            new CdmaInformationRecords.CdmaT53AudioControlInfoRec(
+                                    audioControlInfoRecord.upLink,
+                                    audioControlInfoRecord.downLink);
+                    cdmaInformationRecords = new CdmaInformationRecords(cdmaT53AudioControlInfoRec);
+                    break;
+
+                default:
+                    throw new RuntimeException("RIL_UNSOL_CDMA_INFO_REC: unsupported record. Got "
+                            + CdmaInformationRecords.idToString(id) + " ");
+            }
+
+            if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CDMA_INFO_REC, cdmaInformationRecords);
+            mRil.notifyRegistrantsCdmaInfoRec(cdmaInformationRecords);
+        }
+    }
+
+    /**
+     * Indicates when CDMA radio receives an update of the progress of an OTASP/OTAPA call.
+     * @param indicationType Type of radio indication
+     * @param status CDMA OTA provision status
+     */
+    public void cdmaOtaProvisionStatus(int indicationType, int status) {
+        mRil.processIndication(indicationType);
+
+        int[] response = new int[] {status};
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CDMA_OTA_PROVISION_STATUS, response);
+
+        mRil.mOtaProvisionRegistrants.notifyRegistrants(new AsyncResult(null, response, null));
+    }
+
+
+    /**
+     * Indicates current emergency number list.
+     * @param indicationType Type of radio indication
+     * @param emergencyNumberList Current list of emergency numbers known to radio
+     */
+    public void currentEmergencyNumberList(int indicationType,
+            android.hardware.radio.voice.EmergencyNumber[] emergencyNumberList) {
+        mRil.processIndication(indicationType);
+
+        List<EmergencyNumber> response = new ArrayList<>(emergencyNumberList.length);
+        for (android.hardware.radio.voice.EmergencyNumber enHal : emergencyNumberList) {
+            EmergencyNumber emergencyNumber = new EmergencyNumber(enHal.number,
+                    MccTable.countryCodeForMcc(enHal.mcc), enHal.mnc, enHal.categories,
+                    RILUtils.primitiveArrayToArrayList(enHal.urns), enHal.sources,
+                    EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN);
+            response.add(emergencyNumber);
+        }
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_EMERGENCY_NUMBER_LIST, response);
+
+        // Cache emergency number list from last indication.
+        mRil.cacheEmergencyNumberListIndication(response);
+
+        // Notify emergency number list from radio to registrants
+        mRil.mEmergencyNumberListRegistrants.notifyRegistrants(
+                new AsyncResult(null, response, null));
+    }
+
+    /**
+     * Indicates that the radio system selection module has autonomously entered emergency
+     * callback mode.
+     * @param indicationType Type of radio indication
+     */
+    public void enterEmergencyCallbackMode(int indicationType) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE);
+
+        if (mRil.mEmergencyCallbackModeRegistrant != null) {
+            mRil.mEmergencyCallbackModeRegistrant.notifyRegistrant();
+        }
+    }
+
+    /**
+     * Indicates when Emergency Callback Mode ends. Indicates that the radio system selection module
+     * has proactively exited emergency callback mode.
+     * @param indicationType Type of radio indication
+     */
+    public void exitEmergencyCallbackMode(int indicationType) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE);
+
+        mRil.mExitEmergencyCallbackModeRegistrants.notifyRegistrants();
+    }
+
+    /**
+     * Indicates that network doesn't have in-band information, need to play out-band tone.
+     * @param indicationType Type of radio indication
+     * @param start true = start play ringback tone, false = stop playing ringback tone
+     */
+    public void indicateRingbackTone(int indicationType, boolean start) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogvRet(RIL_UNSOL_RINGBACK_TONE, start);
+
+        mRil.mRingbackToneRegistrants.notifyRegistrants(new AsyncResult(null, start, null));
+    }
+
+    /**
+     * Indicates when Supplementary service(SS) response is received when DIAL/USSD/SS is changed to
+     * SS by call control.
+     * @param indicationType Type of radio indication
+     * @param ss StkCcUnsolSsResult
+     */
+    public void onSupplementaryServiceIndication(int indicationType,
+            android.hardware.radio.voice.StkCcUnsolSsResult ss) {
+        mRil.processIndication(indicationType);
+
+        int num;
+        SsData ssData = new SsData();
+
+        ssData.serviceType = ssData.ServiceTypeFromRILInt(ss.serviceType);
+        ssData.requestType = ssData.RequestTypeFromRILInt(ss.requestType);
+        ssData.teleserviceType = ssData.TeleserviceTypeFromRILInt(ss.teleserviceType);
+        ssData.serviceClass = ss.serviceClass; // This is service class sent in the SS request.
+        ssData.result = ss.result; // This is the result of the SS request.
+
+        if (ssData.serviceType.isTypeCF() && ssData.requestType.isTypeInterrogation()) {
+            android.hardware.radio.voice.CfData cfData = ss.cfData[0];
+            num = cfData.cfInfo.length;
+            ssData.cfInfo = new CallForwardInfo[num];
+
+            for (int i = 0; i < num; i++) {
+                android.hardware.radio.voice.CallForwardInfo cfInfo = cfData.cfInfo[i];
+                ssData.cfInfo[i] = new CallForwardInfo();
+                ssData.cfInfo[i].status = cfInfo.status;
+                ssData.cfInfo[i].reason = cfInfo.reason;
+                ssData.cfInfo[i].serviceClass = cfInfo.serviceClass;
+                ssData.cfInfo[i].toa = cfInfo.toa;
+                ssData.cfInfo[i].number = cfInfo.number;
+                ssData.cfInfo[i].timeSeconds = cfInfo.timeSeconds;
+                mRil.riljLog("[SS Data] CF Info " + i + " : " +  ssData.cfInfo[i]);
+            }
+        } else {
+            android.hardware.radio.voice.SsInfoData ssInfo = ss.ssInfo[0];
+            num = ssInfo.ssInfo.length;
+            ssData.ssInfo = new int[num];
+            for (int i = 0; i < num; i++) {
+                ssData.ssInfo[i] = ssInfo.ssInfo[i];
+                mRil.riljLog("[SS Data] SS Info " + i + " : " +  ssData.ssInfo[i]);
+            }
+        }
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_ON_SS, ssData);
+
+        if (mRil.mSsRegistrant != null) {
+            mRil.mSsRegistrant.notifyRegistrant(new AsyncResult(null, ssData, null));
+        }
+    }
+
+    /**
+     * Indicates that framework/application must reset the uplink mute state.
+     * @param indicationType Type of radio indication
+     */
+    public void resendIncallMute(int indicationType) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESEND_INCALL_MUTE);
+
+        mRil.mResendIncallMuteRegistrants.notifyRegistrants();
+    }
+
+    /**
+     * Indicates when Single Radio Voice Call Continuity (SRVCC) progress state has changed.
+     * @param indicationType Type of radio indication
+     * @param state New SRVCC State
+     */
+    public void srvccStateNotify(int indicationType, int state) {
+        mRil.processIndication(indicationType);
+
+        int[] response = new int[] {state};
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_SRVCC_STATE_NOTIFY, response);
+
+        mRil.writeMetricsSrvcc(state);
+        mRil.mSrvccStateRegistrants.notifyRegistrants(new AsyncResult(null, response, null));
+    }
+
+    /**
+     * Indicates when there is an ALPHA from UICC during Call Control.
+     * @param indicationType Type of radio indication
+     * @param alpha ALPHA string from UICC in UTF-8 format
+     */
+    public void stkCallControlAlphaNotify(int indicationType, String alpha) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_STK_CC_ALPHA_NOTIFY, alpha);
+
+        if (mRil.mCatCcAlphaRegistrant != null) {
+            mRil.mCatCcAlphaRegistrant.notifyRegistrant(new AsyncResult(null, alpha, null));
+        }
+    }
+
+    /**
+     * Indicates when SIM wants application to setup a voice call.
+     * @param indicationType Type of radio indication
+     * @param timeout Timeout value in milliseconds for setting up voice call
+     */
+    public void stkCallSetup(int indicationType, long timeout) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_STK_CALL_SETUP, timeout);
+
+        if (mRil.mCatCallSetUpRegistrant != null) {
+            mRil.mCatCallSetUpRegistrant.notifyRegistrant(new AsyncResult(null, timeout, null));
+        }
+    }
+}
diff --git a/src/java/com/android/internal/telephony/VoiceResponse.java b/src/java/com/android/internal/telephony/VoiceResponse.java
new file mode 100644
index 0000000..1a6e318
--- /dev/null
+++ b/src/java/com/android/internal/telephony/VoiceResponse.java
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2021 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;
+
+import android.hardware.radio.RadioError;
+import android.hardware.radio.RadioResponseInfo;
+import android.hardware.radio.voice.IRadioVoiceResponse;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Interface declaring response functions to solicited radio requests for SIM APIs.
+ */
+public class VoiceResponse extends IRadioVoiceResponse.Stub {
+    private final RIL mRil;
+
+    public VoiceResponse(RIL ril) {
+        mRil = ril;
+    }
+
+    /**
+     * Acknowledge the receipt of radio request sent to the vendor. This must be sent only for
+     * radio request which take long time to respond.
+     * For more details, refer https://source.android.com/devices/tech/connect/ril.html
+     * @param serial Serial no. of the request whose acknowledgement is sent.
+     */
+    public void acknowledgeRequest(int serial) {
+        mRil.processRequestAck(serial);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void acceptCallResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void conferenceResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void dialResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void emergencyDialResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void exitEmergencyCallbackModeResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void explicitCallTransferResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param callForwardInfos points to a vector of CallForwardInfo, one for
+     *        each distinct registered phone number.
+     */
+    public void getCallForwardStatusResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.voice.CallForwardInfo[] callForwardInfos) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+        if (rr != null) {
+            CallForwardInfo[] ret = new CallForwardInfo[callForwardInfos.length];
+            for (int i = 0; i < callForwardInfos.length; i++) {
+                ret[i] = new CallForwardInfo();
+                ret[i].status = callForwardInfos[i].status;
+                ret[i].reason = callForwardInfos[i].reason;
+                ret[i].serviceClass = callForwardInfos[i].serviceClass;
+                ret[i].toa = callForwardInfos[i].toa;
+                ret[i].number = callForwardInfos[i].number;
+                ret[i].timeSeconds = callForwardInfos[i].timeSeconds;
+            }
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, ret);
+            }
+            mRil.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param enable If current call waiting state is disabled, enable = false else true
+     * @param serviceClass If enable, then callWaitingResp[1] must follow, with the TS 27.007
+     *        service class bit vector of services for which call waiting is enabled.
+     *        For example, if callWaitingResp[0] is 1 and callWaitingResp[1] is 3, then call waiting
+     *        is enabled for data and voice and disabled for everything else.
+     */
+    public void getCallWaitingResponse(RadioResponseInfo responseInfo, boolean enable,
+            int serviceClass) {
+        RadioResponse.responseInts(mRil, responseInfo, enable ? 1 : 0, serviceClass);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param status indicates CLIP status
+     */
+    public void getClipResponse(RadioResponseInfo responseInfo, int status) {
+        RadioResponse.responseInts(mRil, responseInfo, status);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param n is "n" parameter from TS 27.007 7.7
+     * @param m is "m" parameter from TS 27.007 7.7
+     */
+    public void getClirResponse(RadioResponseInfo responseInfo, int n, int m) {
+        RadioResponse.responseInts(mRil, responseInfo, n, m);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param calls Current call list
+     */
+    public void getCurrentCallsResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.voice.Call[] calls) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            int num = calls.length;
+            ArrayList<DriverCall> dcCalls = new ArrayList<>(num);
+            DriverCall dc;
+            for (int i = 0; i < num; i++) {
+                dc = RILUtils.convertToDriverCall(calls[i]);
+                dcCalls.add(dc);
+                if (dc.isVoicePrivacy) {
+                    mRil.mVoicePrivacyOnRegistrants.notifyRegistrants();
+                    mRil.riljLog("InCall VoicePrivacy is enabled");
+                } else {
+                    mRil.mVoicePrivacyOffRegistrants.notifyRegistrants();
+                    mRil.riljLog("InCall VoicePrivacy is disabled");
+                }
+            }
+
+            Collections.sort(dcCalls);
+            if ((num == 0) && mRil.mTestingEmergencyCall.getAndSet(false)) {
+                if (mRil.mEmergencyCallbackModeRegistrant != null) {
+                    mRil.riljLog("responseCurrentCalls: call ended, testing emergency call,"
+                            + " notify ECM Registrants");
+                    mRil.mEmergencyCallbackModeRegistrant.notifyRegistrant();
+                }
+            }
+
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, dcCalls);
+            }
+            mRil.processResponseDone(rr, responseInfo, dcCalls);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param fcInfo Contains LastCallFailCause and vendor cause code. GSM failure reasons
+     *        are mapped to cause codes defined in TS 24.008 Annex H where possible. CDMA failure
+     *        reasons are derived from the possible call failure scenarios described in the
+     *        "CDMA IS-2000 Release A (C.S0005-A v6.0)" standard.
+     */
+    public void getLastCallFailCauseResponse(RadioResponseInfo responseInfo,
+            android.hardware.radio.voice.LastCallFailCauseInfo fcInfo) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            LastCallFailCause ret = new LastCallFailCause();
+            ret.causeCode = fcInfo.causeCode;
+            ret.vendorCause = fcInfo.vendorCause;
+            if (responseInfo.error == RadioError.NONE) {
+                RadioResponse.sendMessageResponse(rr.mResult, ret);
+            }
+            mRil.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param enable true for "mute enabled" and false for "mute disabled"
+     */
+    public void getMuteResponse(RadioResponseInfo responseInfo, boolean enable) {
+        RadioResponse.responseInts(mRil, responseInfo, enable ? 1 : 0);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param enable false for Standard Privacy Mode (Public Long Code Mask)
+     *        true for Enhanced Privacy Mode (Private Long Code Mask)
+     */
+    public void getPreferredVoicePrivacyResponse(RadioResponseInfo responseInfo, boolean enable) {
+        RadioResponse.responseInts(mRil, responseInfo, enable ? 1 : 0);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param mode TTY mode
+     */
+    public void getTtyModeResponse(RadioResponseInfo responseInfo, int mode) {
+        RadioResponse.responseInts(mRil, responseInfo, mode);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void handleStkCallSetupRequestFromSimResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void hangupConnectionResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void hangupForegroundResumeBackgroundResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void hangupWaitingOrBackgroundResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void rejectCallResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void sendBurstDtmfResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void sendCdmaFeatureCodeResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void sendDtmfResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void separateConnectionResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setCallForwardResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setCallWaitingResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setClirResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setMuteResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setPreferredVoicePrivacyResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setTtyModeResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void startDtmfResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void stopDtmfResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void switchWaitingOrHoldingAndActiveResponse(RadioResponseInfo responseInfo) {
+        RadioResponse.responseVoid(mRil, responseInfo);
+    }
+}
diff --git a/src/java/com/android/internal/telephony/cdma/SmsMessageConverter.java b/src/java/com/android/internal/telephony/cdma/SmsMessageConverter.java
deleted file mode 100644
index 84da264..0000000
--- a/src/java/com/android/internal/telephony/cdma/SmsMessageConverter.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2008 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.cdma;
-
-import android.hardware.radio.V1_0.CdmaSmsMessage;
-
-import com.android.internal.telephony.SmsMessageBase;
-import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
-import com.android.internal.telephony.cdma.sms.CdmaSmsSubaddress;
-import com.android.internal.telephony.cdma.sms.SmsEnvelope;
-
-/**
- * A Factory class to convert from RIL to Framework SMS
- *
- */
-public class SmsMessageConverter {
-    static final String LOG_TAG = "SmsMessageConverter";
-    static private final String LOGGABLE_TAG = "CDMA:SMS";
-    private static final boolean VDBG = false;
-
-    /**
-     *  Create a "raw" CDMA SmsMessage from a Parcel that was forged in ril.cpp.
-     *  Note: Only primitive fields are set.
-     */
-    public static SmsMessage newCdmaSmsMessageFromRil(
-            CdmaSmsMessage cdmaSmsMessage) {
-        // Note: Parcel.readByte actually reads one Int and masks to byte
-        SmsEnvelope env = new SmsEnvelope();
-        CdmaSmsAddress addr = new CdmaSmsAddress();
-        CdmaSmsSubaddress subaddr = new CdmaSmsSubaddress();
-        byte[] data;
-        byte count;
-        int countInt;
-        int addressDigitMode;
-
-        //currently not supported by the modem-lib: env.mMessageType
-        env.teleService = cdmaSmsMessage.teleserviceId;
-
-        if (cdmaSmsMessage.isServicePresent) {
-            env.messageType = SmsEnvelope.MESSAGE_TYPE_BROADCAST;
-        }
-        else {
-            if (SmsEnvelope.TELESERVICE_NOT_SET == env.teleService) {
-                // assume type ACK
-                env.messageType = SmsEnvelope.MESSAGE_TYPE_ACKNOWLEDGE;
-            } else {
-                env.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
-            }
-        }
-        env.serviceCategory = cdmaSmsMessage.serviceCategory;
-
-        // address
-        addressDigitMode = cdmaSmsMessage.address.digitMode;
-        addr.digitMode = (byte) (0xFF & addressDigitMode);
-        addr.numberMode = (byte) (0xFF & cdmaSmsMessage.address.numberMode);
-        addr.ton = cdmaSmsMessage.address.numberType;
-        addr.numberPlan = (byte) (0xFF & cdmaSmsMessage.address.numberPlan);
-        count = (byte) cdmaSmsMessage.address.digits.size();
-        addr.numberOfDigits = count;
-        data = new byte[count];
-        for (int index=0; index < count; index++) {
-            data[index] = cdmaSmsMessage.address.digits.get(index);
-
-            // convert the value if it is 4-bit DTMF to 8 bit
-            if (addressDigitMode == CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF) {
-                data[index] = SmsMessage.convertDtmfToAscii(data[index]);
-            }
-        }
-
-        addr.origBytes = data;
-
-        subaddr.type = cdmaSmsMessage.subAddress.subaddressType;
-        subaddr.odd = (byte) (cdmaSmsMessage.subAddress.odd ? 1 : 0);
-        count = (byte) cdmaSmsMessage.subAddress.digits.size();
-
-        if (count < 0) {
-            count = 0;
-        }
-
-        // p_cur->sSubAddress.digits[digitCount] :
-
-        data = new byte[count];
-
-        for (int index = 0; index < count; ++index) {
-            data[index] = cdmaSmsMessage.subAddress.digits.get(index);
-        }
-
-        subaddr.origBytes = data;
-
-        /* currently not supported by the modem-lib:
-            env.bearerReply
-            env.replySeqNo
-            env.errorClass
-            env.causeCode
-        */
-
-        // bearer data
-        countInt = cdmaSmsMessage.bearerData.size();
-        if (countInt < 0) {
-            countInt = 0;
-        }
-
-        data = new byte[countInt];
-        for (int index=0; index < countInt; index++) {
-            data[index] = cdmaSmsMessage.bearerData.get(index);
-        }
-        // BD gets further decoded when accessed in SMSDispatcher
-        env.bearerData = data;
-
-        // link the the filled objects to the SMS
-        env.origAddress = addr;
-        env.origSubaddress = subaddr;
-
-        SmsMessage msg = new SmsMessage(addr, env);
-
-        return msg;
-    }
-
-    public static android.telephony.SmsMessage newSmsMessageFromCdmaSmsMessage(
-            CdmaSmsMessage msg) {
-        return new android.telephony.SmsMessage((SmsMessageBase)newCdmaSmsMessageFromRil(msg));
-    }
-}
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index a26ad3c..631bbdd 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -3705,7 +3705,7 @@
         }
     }
 
-    /** Sets the {@link DataCallSessionStats} mock for this phone ID during unit testing. */
+    /** Sets the {@link DataCallSessionStats} mock for this data connection during unit testing. */
     @VisibleForTesting
     public void setDataCallSessionStats(DataCallSessionStats dataCallSessionStats) {
         mDataCallSessionStats = dataCallSessionStats;
diff --git a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
index ead54d3..f2710a9 100644
--- a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
+++ b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
@@ -67,6 +67,7 @@
     public synchronized void onSetupDataCall(@ApnType int apnTypeBitMask) {
         mDataCallSession = getDefaultProto(apnTypeBitMask);
         mStartTime = getTimeMillis();
+        PhoneFactory.getMetricsCollector().registerOngoingDataCallStat(this);
     }
 
     /**
@@ -116,6 +117,7 @@
                 mDataCallSession.oosAtEnd = getIsOos();
                 mDataCallSession.setupFailed = true;
                 mDataCallSession.ongoing = false;
+                PhoneFactory.getMetricsCollector().unregisterOngoingDataCallStat(this);
                 mAtomsStorage.addDataCallSession(mDataCallSession);
                 mDataCallSession = null;
             }
@@ -173,6 +175,7 @@
         mDataCallSession.durationMinutes = convertMillisToMinutes(getTimeMillis() - mStartTime);
         // store for the data call list event, after DataCall is disconnected and entered into
         // inactive mode
+        PhoneFactory.getMetricsCollector().unregisterOngoingDataCallStat(this);
         mAtomsStorage.addDataCallSession(mDataCallSession);
         mDataCallSession = null;
     }
@@ -198,10 +201,45 @@
         }
     }
 
+    /** Add the on-going data call segment to the atom storage. */
+    public synchronized void conclude() {
+        if (mDataCallSession != null) {
+            DataCallSession call = copyOf(mDataCallSession);
+            long nowMillis = getTimeMillis();
+            call.durationMinutes = convertMillisToMinutes(nowMillis - mStartTime);
+            mStartTime = nowMillis;
+            mDataCallSession.ratSwitchCount = 0L;
+            mAtomsStorage.addDataCallSession(call);
+        }
+    }
+
     private static long convertMillisToMinutes(long millis) {
         return Math.round(millis / 60000.0);
     }
 
+    private static DataCallSession copyOf(DataCallSession call) {
+        DataCallSession copy = new DataCallSession();
+        copy.dimension = call.dimension;
+        copy.isMultiSim = call.isMultiSim;
+        copy.isEsim = call.isEsim;
+        copy.apnTypeBitmask = call.apnTypeBitmask;
+        copy.carrierId = call.carrierId;
+        copy.isRoaming = call.isRoaming;
+        copy.ratAtEnd = call.ratAtEnd;
+        copy.oosAtEnd = call.oosAtEnd;
+        copy.ratSwitchCount = call.ratSwitchCount;
+        copy.isOpportunistic = call.isOpportunistic;
+        copy.ipType = call.ipType;
+        copy.setupFailed = call.setupFailed;
+        copy.failureCause = call.failureCause;
+        copy.suggestedRetryMillis = call.suggestedRetryMillis;
+        copy.deactivateReason = call.deactivateReason;
+        copy.durationMinutes = call.durationMinutes;
+        copy.ongoing = call.ongoing;
+        copy.bandAtEnd = call.bandAtEnd;
+        return copy;
+    }
+
     /** Creates a proto for a normal {@code DataCallSession} with default values. */
     private DataCallSession getDefaultProto(@ApnType int apnTypeBitmask) {
         DataCallSession proto = new DataCallSession();
diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
index ae9e30e..6e54230 100644
--- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
+++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
@@ -61,6 +61,8 @@
 import java.util.Comparator;
 import java.util.List;
 import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * Implements statsd pullers for Telephony.
@@ -102,6 +104,7 @@
     private PersistAtomsStorage mStorage;
     private final StatsManager mStatsManager;
     private final AirplaneModeStats mAirplaneModeStats;
+    private final Set<DataCallSessionStats> mOngoingDataCallStats = ConcurrentHashMap.newKeySet();
     private static final Random sRandom = new Random();
 
     public MetricsCollector(Context context) {
@@ -183,6 +186,19 @@
         return mStorage;
     }
 
+    /**
+     * Registers a {@link DataCallSessionStats} which will be pinged for on-going data calls when
+     * data call atoms are pulled.
+     */
+    public void registerOngoingDataCallStat(DataCallSessionStats call) {
+        mOngoingDataCallStats.add(call);
+    }
+
+    /** Unregisters a {@link DataCallSessionStats} when it no longer handles an active data call. */
+    public void unregisterOngoingDataCallStat(DataCallSessionStats call) {
+        mOngoingDataCallStats.remove(call);
+    }
+
     private static int pullSimSlotState(List<StatsEvent> data) {
         SimSlotState state;
         try {
@@ -289,6 +305,11 @@
     }
 
     private int pullDataCallSession(List<StatsEvent> data) {
+        // Include ongoing data call segments
+        for (DataCallSessionStats stats : mOngoingDataCallStats) {
+            stats.conclude();
+        }
+
         DataCallSession[] dataCallSessions = mStorage.getDataCallSessions(MIN_COOLDOWN_MILLIS);
         if (dataCallSessions != null) {
             Arrays.stream(dataCallSessions)
diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
index 4f0302f..6796dad 100644
--- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
+++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
@@ -233,8 +233,17 @@
 
     /** Adds a data call session to the storage. */
     public synchronized void addDataCallSession(DataCallSession dataCall) {
-        mAtoms.dataCallSession =
-                insertAtRandomPlace(mAtoms.dataCallSession, dataCall, mMaxNumDataCallSessions);
+        int index = findIndex(dataCall);
+        if (index >= 0) {
+            DataCallSession existingCall = mAtoms.dataCallSession[index];
+            dataCall.ratSwitchCount += existingCall.ratSwitchCount;
+            dataCall.durationMinutes += existingCall.durationMinutes;
+            mAtoms.dataCallSession[index] = dataCall;
+        } else {
+            mAtoms.dataCallSession =
+                    insertAtRandomPlace(mAtoms.dataCallSession, dataCall, mMaxNumDataCallSessions);
+        }
+
         saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_UPDATE_MILLIS);
     }
 
@@ -730,6 +739,19 @@
     }
 
     /**
+     * Returns the index of data call session that has the same random dimension as the given one,
+     * or -1 if it does not exist.
+     */
+    private int findIndex(DataCallSession key) {
+        for (int i = 0; i < mAtoms.dataCallSession.length; i++) {
+            if (mAtoms.dataCallSession[i].dimension == key.dimension) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
      * Inserts a new element in a random position in an array with a maximum size, replacing the
      * least recent item if possible.
      */
diff --git a/src/java/com/android/internal/telephony/uicc/AdnCapacity.java b/src/java/com/android/internal/telephony/uicc/AdnCapacity.java
index 300759a..d951c71 100644
--- a/src/java/com/android/internal/telephony/uicc/AdnCapacity.java
+++ b/src/java/com/android/internal/telephony/uicc/AdnCapacity.java
@@ -16,7 +16,6 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.hardware.radio.V1_6.PhonebookCapacity;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -55,21 +54,6 @@
         mMaxAnrLength = maxAnrLength;
     }
 
-    public AdnCapacity(PhonebookCapacity pbCap) {
-        if (pbCap != null) {
-            mMaxAdnCount = pbCap.maxAdnRecords;
-            mUsedAdnCount = pbCap.usedAdnRecords;
-            mMaxEmailCount = pbCap.maxEmailRecords;
-            mUsedEmailCount = pbCap.usedEmailRecords;
-            mMaxAnrCount = pbCap.maxAdditionalNumberRecords;
-            mUsedAnrCount = pbCap.usedAdditionalNumberRecords;
-            mMaxNameLength = pbCap.maxNameLen;
-            mMaxNumberLength = pbCap.maxNumberLen;
-            mMaxEmailLength = pbCap.maxEmailLen;
-            mMaxAnrLength = pbCap.maxAdditionalNumberLen;
-        }
-    }
-
     public int getMaxAdnCount() {
         return mMaxAdnCount;
     }
diff --git a/src/java/com/android/internal/telephony/uicc/IccCardApplicationStatus.java b/src/java/com/android/internal/telephony/uicc/IccCardApplicationStatus.java
index fb8b111..840a6b3 100644
--- a/src/java/com/android/internal/telephony/uicc/IccCardApplicationStatus.java
+++ b/src/java/com/android/internal/telephony/uicc/IccCardApplicationStatus.java
@@ -155,7 +155,7 @@
     // null terminated string
     public String         app_label;
     // applicable to USIM and CSIM
-    public int            pin1_replaced;
+    public boolean        pin1_replaced;
     public PinState       pin1;
     public PinState       pin2;
 
diff --git a/src/java/com/android/internal/telephony/uicc/PinStorage.java b/src/java/com/android/internal/telephony/uicc/PinStorage.java
index bad2d95..2885124 100644
--- a/src/java/com/android/internal/telephony/uicc/PinStorage.java
+++ b/src/java/com/android/internal/telephony/uicc/PinStorage.java
@@ -214,8 +214,10 @@
     }
 
     /** Store the {@code pin} for the {@code slotId}. */
-    public synchronized void storePin(String pin, int slotId, String iccId) {
-        if (!validatePin(pin) || !validateIccid(iccId) || !validateSlotId(slotId)) {
+    public synchronized void storePin(String pin, int slotId) {
+        String iccid = getIccid(slotId);
+
+        if (!validatePin(pin) || !validateIccid(iccid) || !validateSlotId(slotId)) {
             // We are unable to store the PIN. At least clear the old one, if present.
             loge("storePin[%d] - Invalid PIN, slotId or ICCID", slotId);
             clearPin(slotId);
@@ -229,7 +231,7 @@
         logd("storePin[%d]", slotId);
 
         StoredPin storedPin = new StoredPin();
-        storedPin.iccid = iccId;
+        storedPin.iccid = iccid;
         storedPin.pin = pin;
         storedPin.slotId = slotId;
         storedPin.status = PinStatus.AVAILABLE;
@@ -929,7 +931,7 @@
     }
 
     /** Returns the ICCID of the SIM card for the given {@code slotId}. */
-    public String getIccid(int slotId) {
+    private String getIccid(int slotId) {
         Phone phone = PhoneFactory.getPhone(slotId);
         return phone != null ? phone.getFullIccSerialNumber() : "";
     }
diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java
index aed860b..9958bfb 100644
--- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java
@@ -308,7 +308,9 @@
     @Override
     public void setMsisdnNumber(String alphaTag, String number,
             Message onComplete) {
-
+        if (mDestroyed.get()) {
+            return;
+        }
         // If the SIM card is locked by PIN, we will set EF_MSISDN fail.
         // In that case, msisdn and msisdnTag should not be update.
         mNewMsisdn = number;
@@ -412,6 +414,9 @@
     @Override
     public void
     setVoiceMessageWaiting(int line, int countWaiting) {
+        if (mDestroyed.get()) {
+            return;
+        }
         if (line != 1) {
             // only profile 1 is supported
             return;
@@ -515,7 +520,9 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     @Override
     public void setVoiceCallForwardingFlag(int line, boolean enable, String dialNumber) {
-
+        if (mDestroyed.get()) {
+            return;
+        }
         if (line != 1) return; // only line 1 is supported
 
         mCallForwardingStatus = enable ? CALL_FORWARDING_STATUS_ENABLED :
@@ -1514,6 +1521,9 @@
     //***** Private methods
 
     private void setVoiceMailByCountry (String spn) {
+        if (mDestroyed.get()) {
+            return;
+        }
         if (mVmConfig.containsCarrier(spn)) {
             mIsVoiceMailFixed = true;
             mVoiceMailNum = mVmConfig.getVoiceMailNumber(spn);
diff --git a/src/java/com/android/internal/telephony/uicc/SimPhonebookRecord.java b/src/java/com/android/internal/telephony/uicc/SimPhonebookRecord.java
index c6c7d6d..82caded 100644
--- a/src/java/com/android/internal/telephony/uicc/SimPhonebookRecord.java
+++ b/src/java/com/android/internal/telephony/uicc/SimPhonebookRecord.java
@@ -16,15 +16,12 @@
 
 package com.android.internal.telephony.uicc;
 
-import android.hardware.radio.V1_6.PhonebookRecordInfo;
-import android.text.TextUtils;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
+import android.text.TextUtils;
 
 import com.android.internal.telephony.util.ArrayUtils;
 
 import java.util.Arrays;
-import java.util.List;
 
 /**
  * Represents a Phonebook entry from the SIM.
@@ -39,7 +36,6 @@
     private String[] mEmails;
     private String[] mAdditionalNumbers;
 
-    // Instance methods
     public SimPhonebookRecord (int recordIndex, String alphaTag, String number,
                String[] emails, String[] adNumbers) {
         mRecordIndex = recordIndex;
@@ -49,42 +45,11 @@
         if (adNumbers != null) {
             mAdditionalNumbers = new String[adNumbers.length];
             for (int i = 0 ; i < adNumbers.length; i++) {
-                mAdditionalNumbers[i] =
-                        convertRecordFormatToNumber(adNumbers[i]);
+                mAdditionalNumbers[i] = convertRecordFormatToNumber(adNumbers[i]);
             }
         }
     }
 
-    public SimPhonebookRecord(PhonebookRecordInfo recInfo) {
-        mRecordIndex = recInfo.recordId;
-        mAlphaTag = recInfo.name;
-        mNumber = recInfo.number;
-        mEmails = recInfo.emails == null ? null
-                : recInfo.emails.toArray(new String[recInfo.emails.size()]);
-        mAdditionalNumbers = recInfo.additionalNumbers == null ? null
-                : recInfo.additionalNumbers.toArray(
-                        new String[recInfo.additionalNumbers.size()]);
-    }
-
-    public SimPhonebookRecord() {}
-
-    public PhonebookRecordInfo toPhonebookRecordInfo() {
-        PhonebookRecordInfo pbRecordInfo = new PhonebookRecordInfo();
-        pbRecordInfo.recordId = mRecordIndex;
-        pbRecordInfo.name = convertNullToEmptyString(mAlphaTag);
-        pbRecordInfo.number = convertNullToEmptyString(convertNumberToRecordFormat(mNumber));
-        if (mEmails != null) {
-            for (String email : mEmails) {
-                pbRecordInfo.emails.add(email);
-            }
-        }
-        if (mAdditionalNumbers != null) {
-            for (String addNum : mAdditionalNumbers) {
-                pbRecordInfo.additionalNumbers.add(convertNumberToRecordFormat(addNum));
-            }
-        }
-        return pbRecordInfo;
-    }
     public int getRecordIndex() {
         return mRecordIndex;
     }
@@ -114,19 +79,6 @@
                 .replace( '?', PhoneNumberUtils.WILD );
     }
 
-    /**
-     * convert the GSM pause/wild/wait character to the phone number in the SIM pb record format
-     */
-    private static String convertNumberToRecordFormat(String input) {
-        return input == null ? null : input.replace(PhoneNumberUtils.WAIT, 'e')
-                .replace(PhoneNumberUtils.PAUSE, 'T')
-                .replace(PhoneNumberUtils.WILD, '?');
-    }
-
-    private static String convertNullToEmptyString(String string) {
-        return string != null ? string : "";
-    }
-
     public boolean isEmpty() {
         return TextUtils.isEmpty(mAlphaTag)
                 && TextUtils.isEmpty(mNumber)
@@ -158,17 +110,8 @@
         private String[] mAdditionalNumbers;
 
         public SimPhonebookRecord build() {
-            SimPhonebookRecord record = new SimPhonebookRecord();
-            record.mAlphaTag = mAlphaTag;
-            record.mRecordIndex = mRecordIndex;
-            record.mNumber = mNumber;
-            if (mEmails != null) {
-                record.mEmails = mEmails;
-            }
-            if (mAdditionalNumbers != null) {
-                record.mAdditionalNumbers = mAdditionalNumbers;
-            }
-            return record;
+            return new SimPhonebookRecord(mRecordIndex, mAlphaTag, mNumber, mEmails,
+                    mAdditionalNumbers);
         }
 
         public Builder setRecordIndex(int index) {
diff --git a/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java b/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java
index e876efd..3839610 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java
@@ -113,7 +113,7 @@
         mPersoSubState = as.perso_substate;
         mAid = as.aid;
         mAppLabel = as.app_label;
-        mPin1Replaced = (as.pin1_replaced != 0);
+        mPin1Replaced = as.pin1_replaced;
         mPin1State = as.pin1;
         mPin2State = as.pin2;
         mIgnoreApp = false;
@@ -151,7 +151,7 @@
             mPersoSubState = as.perso_substate;
             mAid = as.aid;
             mAppLabel = as.app_label;
-            mPin1Replaced = (as.pin1_replaced != 0);
+            mPin1Replaced = as.pin1_replaced;
             mPin1State = as.pin1;
             mPin2State = as.pin2;
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityLteTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityLteTest.java
index d3b3e59..3eb8d21 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellIdentityLteTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellIdentityLteTest.java
@@ -263,7 +263,7 @@
                 new android.hardware.radio.V1_5.CellIdentityLte();
         cid.bands = Arrays.stream(BANDS).boxed().collect(Collectors.toCollection(ArrayList::new));
 
-        CellIdentityLte cellIdentityLte = new CellIdentityLte(cid);
+        CellIdentityLte cellIdentityLte = RILUtils.convertHalCellIdentityLte(cid);
         assertTrue(Arrays.equals(cellIdentityLte.getBands(), BANDS));
 
     }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthNrTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthNrTest.java
index a294471..02787df 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthNrTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthNrTest.java
@@ -108,7 +108,7 @@
         nrSignalStrength.base.ssSinr = SSSINR;
 
         // THEN the get method should return the correct value
-        CellSignalStrengthNr css = new CellSignalStrengthNr(nrSignalStrength);
+        CellSignalStrengthNr css = RILUtils.convertHalNrSignalStrength(nrSignalStrength);
         assertThat(css.getCsiRsrp()).isEqualTo(CSIRSRP);
         assertThat(css.getCsiRsrq()).isEqualTo(CSIRSRQ);
         assertThat(css.getCsiSinr()).isEqualTo(CSISINR);
@@ -134,7 +134,7 @@
         nrSignalStrength.base.ssSinr = CellInfo.UNAVAILABLE;
 
         // THEN the get method should return unavailable value
-        CellSignalStrengthNr css = new CellSignalStrengthNr(nrSignalStrength);
+        CellSignalStrengthNr css = RILUtils.convertHalNrSignalStrength(nrSignalStrength);
         assertThat(css.getCsiRsrp()).isEqualTo(CellInfo.UNAVAILABLE);
         assertThat(css.getCsiRsrq()).isEqualTo(CellInfo.UNAVAILABLE);
         assertThat(css.getCsiSinr()).isEqualTo(CellInfo.UNAVAILABLE);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
index 1c14f8e..149115a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
@@ -2002,7 +2002,7 @@
                 new android.hardware.radio.V1_5.CellIdentityLte();
         initializeCellIdentityLte_1_5(halCellIdentity, false, true);
 
-        CellIdentityLte cellIdentity = new CellIdentityLte(halCellIdentity);
+        CellIdentityLte cellIdentity = RILUtils.convertHalCellIdentityLte(halCellIdentity);
 
         assertEquals(CSG_INDICATION,
                 cellIdentity.getClosedSubscriberGroupInfo().getCsgIndicator());
@@ -2018,7 +2018,7 @@
                 new android.hardware.radio.V1_5.CellIdentityLte();
         initializeCellIdentityLte_1_5(halCellIdentity, true, false);
 
-        CellIdentityLte cellIdentity = new CellIdentityLte(halCellIdentity);
+        CellIdentityLte cellIdentity = RILUtils.convertHalCellIdentityLte(halCellIdentity);
 
         Set<String> additionalPlmns = new HashSet<>();
         Collections.addAll(additionalPlmns, ADDITIONAL_PLMNS);
@@ -2047,7 +2047,7 @@
                 new android.hardware.radio.V1_5.CellIdentityWcdma();
         initializeCellIdentityWcdma_1_5(halCellIdentity, false, true);
 
-        CellIdentityWcdma cellIdentity = new CellIdentityWcdma(halCellIdentity);
+        CellIdentityWcdma cellIdentity = RILUtils.convertHalCellIdentityWcdma(halCellIdentity);
 
         assertEquals(CSG_INDICATION,
                 cellIdentity.getClosedSubscriberGroupInfo().getCsgIndicator());
@@ -2063,7 +2063,7 @@
                 new android.hardware.radio.V1_5.CellIdentityWcdma();
         initializeCellIdentityWcdma_1_5(halCellIdentity, true, false);
 
-        CellIdentityWcdma cellIdentity = new CellIdentityWcdma(halCellIdentity);
+        CellIdentityWcdma cellIdentity = RILUtils.convertHalCellIdentityWcdma(halCellIdentity);
 
         Set<String> additionalPlmns = new HashSet<>();
         Collections.addAll(additionalPlmns, ADDITIONAL_PLMNS);
@@ -2092,7 +2092,7 @@
                 new android.hardware.radio.V1_5.CellIdentityTdscdma();
         initializeCellIdentityTdscdma_1_5(halCellIdentity, false, true);
 
-        CellIdentityTdscdma cellIdentity = new CellIdentityTdscdma(halCellIdentity);
+        CellIdentityTdscdma cellIdentity = RILUtils.convertHalCellIdentityTdscdma(halCellIdentity);
 
         assertEquals(CSG_INDICATION,
                 cellIdentity.getClosedSubscriberGroupInfo().getCsgIndicator());
@@ -2108,7 +2108,7 @@
                 new android.hardware.radio.V1_5.CellIdentityTdscdma();
         initializeCellIdentityTdscdma_1_5(halCellIdentity, true, false);
 
-        CellIdentityTdscdma cellIdentity = new CellIdentityTdscdma(halCellIdentity);
+        CellIdentityTdscdma cellIdentity = RILUtils.convertHalCellIdentityTdscdma(halCellIdentity);
 
         Set<String> additionalPlmns = new HashSet<>();
         Collections.addAll(additionalPlmns, ADDITIONAL_PLMNS);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java
index 0dc9647..c9a16f5 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java
@@ -26,6 +26,7 @@
 import androidx.test.filters.FlakyTest;
 
 import com.android.internal.telephony.GsmAlphabet;
+import com.android.internal.telephony.RILUtils;
 import com.android.internal.telephony.cdma.sms.BearerData;
 import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
 import com.android.internal.telephony.cdma.sms.SmsEnvelope;
@@ -120,7 +121,7 @@
         for (byte b : bearerData) {
             msg.bearerData.add(b);
         }
-        SmsMessage message = SmsMessageConverter.newCdmaSmsMessageFromRil(msg);
+        SmsMessage message = RILUtils.convertHalCdmaSmsMessage(msg);
         return message;
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java
index df158c1..f200a0f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java
@@ -47,6 +47,7 @@
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch;
 import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState;
+import com.android.internal.telephony.nano.PersistAtomsProto.DataCallSession;
 import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationStats;
 import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationTermination;
 import com.android.internal.telephony.nano.PersistAtomsProto.PersistAtoms;
@@ -130,6 +131,10 @@
     private ImsRegistrationStats[] mImsRegistrationStats;
     private ImsRegistrationTermination[] mImsRegistrationTerminations;
 
+    // Data call sessions
+    private DataCallSession mDataCallSession0;
+    private DataCallSession mDataCallSession1;
+
     private void makeTestData() {
         // MO call with SRVCC (LTE to UMTS)
         mCall1Proto = new VoiceCallSession();
@@ -432,6 +437,24 @@
                 new ImsRegistrationTermination[] {
                     mImsRegistrationTerminationLte, mImsRegistrationTerminationWifi
                 };
+
+        mDataCallSession0 = new DataCallSession();
+        mDataCallSession0.dimension = 111;
+        mDataCallSession0.carrierId = CARRIER1_ID;
+        mDataCallSession0.oosAtEnd = false;
+        mDataCallSession0.ratSwitchCount = 3L;
+        mDataCallSession0.setupFailed = false;
+        mDataCallSession0.durationMinutes = 20;
+        mDataCallSession0.ongoing = true;
+
+        mDataCallSession1 = new DataCallSession();
+        mDataCallSession1.dimension = 222;
+        mDataCallSession1.carrierId = CARRIER2_ID;
+        mDataCallSession1.oosAtEnd = true;
+        mDataCallSession1.ratSwitchCount = 1L;
+        mDataCallSession1.setupFailed = false;
+        mDataCallSession1.durationMinutes = 5;
+        mDataCallSession1.ongoing = false;
     }
 
     private static class TestablePersistAtomsStorage extends PersistAtomsStorage {
@@ -1273,6 +1296,53 @@
         inOrder.verifyNoMoreInteractions();
     }
 
+    @Test
+    @SmallTest
+    public void addDataCallSession_newEntry()
+            throws Exception {
+        createEmptyTestFile();
+        mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+
+        mPersistAtomsStorage.addDataCallSession(mDataCallSession0);
+        mPersistAtomsStorage.addDataCallSession(mDataCallSession1);
+        mPersistAtomsStorage.incTimeMillis(100L);
+
+        // there should be 2 data calls
+        verifyCurrentStateSavedToFileOnce();
+        DataCallSession[] dataCalls = mPersistAtomsStorage.getDataCallSessions(0L);
+        assertProtoArrayEqualsIgnoringOrder(
+                new DataCallSession[] {mDataCallSession0, mDataCallSession1},
+                dataCalls);
+    }
+
+    @Test
+    @SmallTest
+    public void addDataCallSession_existingEntry()
+            throws Exception {
+        createEmptyTestFile();
+        mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+        DataCallSession newDataCallSession0 = copyOf(mDataCallSession0);
+        newDataCallSession0.ongoing = false;
+        newDataCallSession0.ratAtEnd = TelephonyManager.NETWORK_TYPE_LTE;
+        newDataCallSession0.durationMinutes = 10;
+        newDataCallSession0.ratSwitchCount = 5;
+        DataCallSession totalDataCallSession0 = copyOf(newDataCallSession0);
+        totalDataCallSession0.durationMinutes =
+                mDataCallSession0.durationMinutes + newDataCallSession0.durationMinutes;
+        totalDataCallSession0.ratSwitchCount =
+                mDataCallSession0.ratSwitchCount + newDataCallSession0.ratSwitchCount;
+
+        mPersistAtomsStorage.addDataCallSession(mDataCallSession0);
+        mPersistAtomsStorage.addDataCallSession(newDataCallSession0);
+        mPersistAtomsStorage.incTimeMillis(100L);
+
+        // there should be 1 data call
+        verifyCurrentStateSavedToFileOnce();
+        DataCallSession[] dataCalls = mPersistAtomsStorage.getDataCallSessions(0L);
+        assertProtoArrayEqualsIgnoringOrder(
+                new DataCallSession[] {totalDataCallSession0}, dataCalls);
+    }
+
     /* Utilities */
 
     private void createEmptyTestFile() throws Exception {
@@ -1351,6 +1421,11 @@
         return ImsRegistrationTermination.parseFrom(MessageNano.toByteArray(source));
     }
 
+    private static DataCallSession copyOf(DataCallSession source)
+            throws Exception {
+        return DataCallSession.parseFrom(MessageNano.toByteArray(source));
+    }
+
     private void assertAllPullTimestampEquals(long timestamp) {
         assertEquals(
                 timestamp,
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/PinStorageTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/PinStorageTest.java
index f0dee2b..a26c0f9 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/PinStorageTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/PinStorageTest.java
@@ -106,7 +106,7 @@
     @Test
     @SmallTest
     public void storePin_withoutReboot_pinCannotBeRetrieved() {
-        mPinStorage.storePin("1234", 0, mPinStorage.getIccid(0));
+        mPinStorage.storePin("1234", 0);
 
         assertThat(mPinStorage.getPin(0, ICCID_1)).isEqualTo("");
     }
@@ -114,7 +114,7 @@
     @Test
     @SmallTest
     public void storePin_normalReboot_pinCannotBeRetrieved() {
-        mPinStorage.storePin("1234", 0, mPinStorage.getIccid(0));
+        mPinStorage.storePin("1234", 0);
 
         simulateReboot();
 
@@ -124,7 +124,7 @@
     @Test
     @SmallTest
     public void storePin_crash_pinCannotBeRetrieved() {
-        mPinStorage.storePin("1234", 0, mPinStorage.getIccid(0));
+        mPinStorage.storePin("1234", 0);
 
         // Simulate crash
         mPinStorage = new PinStorage(mContext);
@@ -136,7 +136,7 @@
     @Test
     @SmallTest
     public void storePin_unattendedReboot_pinCanBeRetrievedOnce() {
-        mPinStorage.storePin("1234", 0, mPinStorage.getIccid(0));
+        mPinStorage.storePin("1234", 0);
 
         int result = mPinStorage.prepareUnattendedReboot();
         assertThat(result).isEqualTo(TelephonyManager.PREPARE_UNATTENDED_REBOOT_SUCCESS);
@@ -156,7 +156,7 @@
         when(mKeyguardManager.isDeviceLocked()).thenReturn(true);
         simulateReboot();
 
-        mPinStorage.storePin("1234", 0, mPinStorage.getIccid(0));
+        mPinStorage.storePin("1234", 0);
 
         int result = mPinStorage.prepareUnattendedReboot();
         assertThat(result).isEqualTo(TelephonyManager.PREPARE_UNATTENDED_REBOOT_ERROR);
@@ -170,7 +170,7 @@
     @Test
     @SmallTest
     public void storePin_unattendedReboot_pinIsRemovedAfterDelay() {
-        mPinStorage.storePin("1234", 0, mPinStorage.getIccid(0));
+        mPinStorage.storePin("1234", 0);
 
         int result = mPinStorage.prepareUnattendedReboot();
         assertThat(result).isEqualTo(TelephonyManager.PREPARE_UNATTENDED_REBOOT_SUCCESS);
@@ -195,7 +195,7 @@
     @Test
     @SmallTest
     public void storePin_unattendedRebootNotDone_pinCannotBeRetrieved() {
-        mPinStorage.storePin("1234", 0, mPinStorage.getIccid(0));
+        mPinStorage.storePin("1234", 0);
 
         int result = mPinStorage.prepareUnattendedReboot();
         assertThat(result).isEqualTo(TelephonyManager.PREPARE_UNATTENDED_REBOOT_SUCCESS);
@@ -211,7 +211,7 @@
     @Test
     @SmallTest
     public void storePin_unattendedReboot_iccidChange() {
-        mPinStorage.storePin("1234", 0, mPinStorage.getIccid(0));
+        mPinStorage.storePin("1234", 0);
 
         int result = mPinStorage.prepareUnattendedReboot();
         assertThat(result).isEqualTo(TelephonyManager.PREPARE_UNATTENDED_REBOOT_SUCCESS);
@@ -232,7 +232,7 @@
     @Test
     @SmallTest
     public void clearPin_pinCannotBeRetrieved() {
-        mPinStorage.storePin("1234", 0, mPinStorage.getIccid(0));
+        mPinStorage.storePin("1234", 0);
         mPinStorage.clearPin(0);
 
         int result = mPinStorage.prepareUnattendedReboot();
@@ -246,8 +246,8 @@
     @Test
     @SmallTest
     public void storePin_pinChanged_pinIsUpdated() {
-        mPinStorage.storePin("1234", 0, mPinStorage.getIccid(0));
-        mPinStorage.storePin("5678", 0, mPinStorage.getIccid(0));
+        mPinStorage.storePin("1234", 0);
+        mPinStorage.storePin("5678", 0);
 
         int result = mPinStorage.prepareUnattendedReboot();
         assertThat(result).isEqualTo(TelephonyManager.PREPARE_UNATTENDED_REBOOT_SUCCESS);
@@ -260,7 +260,7 @@
     @Test
     @SmallTest
     public void storePin_pinTooShort_pinIsNotStored() {
-        mPinStorage.storePin("12", 0, mPinStorage.getIccid(0));
+        mPinStorage.storePin("12", 0);
 
         int result = mPinStorage.prepareUnattendedReboot();
         assertThat(result).isEqualTo(TelephonyManager.PREPARE_UNATTENDED_REBOOT_SUCCESS);
@@ -273,7 +273,7 @@
     @Test
     @SmallTest
     public void storePin_pinTooLong_pinIsNotStored() {
-        mPinStorage.storePin("123456789", 0, mPinStorage.getIccid(0));
+        mPinStorage.storePin("123456789", 0);
 
         int result = mPinStorage.prepareUnattendedReboot();
         assertThat(result).isEqualTo(TelephonyManager.PREPARE_UNATTENDED_REBOOT_SUCCESS);
@@ -288,7 +288,7 @@
     public void storePin_invalidIccid_pinIsNotStored() {
         doReturn(ICCID_INVALID).when(mPhone).getFullIccSerialNumber();
 
-        mPinStorage.storePin("1234", 0, mPinStorage.getIccid(0));
+        mPinStorage.storePin("1234", 0);
         int result = mPinStorage.prepareUnattendedReboot();
 
         simulateReboot();
@@ -302,7 +302,7 @@
         mContextFixture.putBooleanResource(
                 R.bool.config_allow_pin_storage_for_unattended_reboot, false);
 
-        mPinStorage.storePin("1234", 0, mPinStorage.getIccid(0));
+        mPinStorage.storePin("1234", 0);
 
         int result = mPinStorage.prepareUnattendedReboot();
         assertThat(result).isEqualTo(TelephonyManager.PREPARE_UNATTENDED_REBOOT_SUCCESS);
@@ -321,7 +321,7 @@
         when(mUiccController.getUiccProfileForPhone(anyInt())).thenReturn(mUiccProfile);
         when(mUiccCardApplication3gpp.getPin1State()).thenReturn(PINSTATE_ENABLED_VERIFIED);
 
-        mPinStorage.storePin("1234", 0, mPinStorage.getIccid(0));
+        mPinStorage.storePin("1234", 0);
 
         int result = mPinStorage.prepareUnattendedReboot();
         assertThat(result).isEqualTo(TelephonyManager.PREPARE_UNATTENDED_REBOOT_PIN_REQUIRED);
@@ -339,7 +339,7 @@
                 CarrierConfigManager.KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL, false);
         when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(carrierConfigs);
 
-        mPinStorage.storePin("1234", 0, mPinStorage.getIccid(0));
+        mPinStorage.storePin("1234", 0);
 
         int result = mPinStorage.prepareUnattendedReboot();
         assertThat(result).isEqualTo(TelephonyManager.PREPARE_UNATTENDED_REBOOT_SUCCESS);
@@ -352,7 +352,7 @@
     @Test
     @SmallTest
     public void storePin_changeToDisabledInCarrierConfig_pinIsRemoved() {
-        mPinStorage.storePin("1234", 0, mPinStorage.getIccid(0));
+        mPinStorage.storePin("1234", 0);
 
         // Simulate change in the carrier configuration
         PersistableBundle carrierConfigs = new PersistableBundle();
@@ -375,7 +375,7 @@
     @Test
     @SmallTest
     public void storePin_simIsRemoved_pinIsRemoved() {
-        mPinStorage.storePin("1234", 0, mPinStorage.getIccid(0));
+        mPinStorage.storePin("1234", 0);
 
         // SIM is removed
         final Intent intent = new Intent(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED);
@@ -395,7 +395,7 @@
     @Test
     @SmallTest
     public void storePin_simReadyAfterUnattendedReboot_pinIsRemoved() {
-        mPinStorage.storePin("1234", 0, mPinStorage.getIccid(0));
+        mPinStorage.storePin("1234", 0);
 
         int result = mPinStorage.prepareUnattendedReboot();
         assertThat(result).isEqualTo(TelephonyManager.PREPARE_UNATTENDED_REBOOT_SUCCESS);