Merge "Added calls to startHandover and cancelHandover"
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index e4298ad..a7e5b0a 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -1831,7 +1831,7 @@
      */
     void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
                        boolean allowRoaming, int reason, LinkProperties linkProperties,
-                       Message result);
+                       int pduSessionId, Message result);
 
     /**
      * Deactivate packet data connection
@@ -2543,4 +2543,39 @@
      * @param result Message will be sent back to handler and result.obj will be the AsycResult.
      */
     default void getBarringInfo(Message result) {};
+
+    /**
+     * Allocates a pdu session id
+     *
+     * AsyncResult.result is the allocated pdu session id
+     *
+     * @param result Message will be sent back to handler and result.obj will be the AsycResult.
+     *
+     */
+    default void allocatePduSessionId(Message result) {};
+
+    /**
+     * Release the pdu session id
+     *
+     * @param result Message that will be sent back to handler.
+     * @param pduSessionId The id that was allocated and should now be released.
+     *
+     */
+    default void releasePduSessionId(Message result, int pduSessionId) {};
+
+    /**
+     * Indicates that a handover has started
+     *
+     * @param result Message that will be sent back to handler.
+     * @param callId Identifier associated with the data call
+     */
+    default void startHandover(Message result, int callId) {};
+
+    /**
+     * Indicates that a handover has been cancelled
+     *
+     * @param result Message that will be sent back to handler.
+     * @param callId Identifier associated with the data call
+     */
+    default void cancelHandover(Message result, int callId) {};
 }
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 1823c1d..1882c85 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -1893,8 +1893,7 @@
     @Override
     public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
                               boolean allowRoaming, int reason, LinkProperties linkProperties,
-                              Message result) {
-
+                              int pduSessionId, Message result) {
         IRadio radioProxy = getRadioProxy(result);
 
         if (radioProxy != null) {
@@ -1942,11 +1941,12 @@
                                 + ",accessNetworkType="
                                 + AccessNetworkType.toString(accessNetworkType) + ",isRoaming="
                                 + isRoaming + ",allowRoaming=" + allowRoaming + "," + dataProfile
-                                + ",addresses=" + addresses15 + ",dnses=" + dnses);
+                                + ",addresses=" + addresses15 + ",dnses=" + dnses
+                                + ",pduSessionId=" + pduSessionId);
                     }
 
                     radioProxy16.setupDataCall_1_6(rr.mSerial, accessNetworkType, dpi, allowRoaming,
-                            reason, addresses15, dnses);
+                            reason, addresses15, dnses, pduSessionId);
                 } else if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_5)) {
                     // IRadio V1.5
                     android.hardware.radio.V1_5.IRadio radioProxy15 =
@@ -5596,7 +5596,115 @@
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void allocatePduSessionId(Message result) {
+        android.hardware.radio.V1_6.IRadio radioProxy16 = getRadioV16(result);
+
+        if (radioProxy16 != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_ALLOCATE_PDU_SESSION_ID, result,
+                    mRILDefaultWorkSource);
+            if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+            try {
+                radioProxy16.allocatePduSessionId(rr.mSerial);
+            } catch (RemoteException e) {
+                handleRadioProxyExceptionForRR(rr, "allocatePduSessionId", e);
+            }
+        } else {
+            AsyncResult.forMessage(result, null,
+                    CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+            result.sendToTarget();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void releasePduSessionId(Message result, int pduSessionId) {
+        android.hardware.radio.V1_6.IRadio radioProxy16 = getRadioV16(result);
+
+        if (radioProxy16 != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_RELEASE_PDU_SESSION_ID, result,
+                    mRILDefaultWorkSource);
+            if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+            try {
+                radioProxy16.releasePduSessionId(rr.mSerial, pduSessionId);
+            } catch (RemoteException e) {
+                handleRadioProxyExceptionForRR(rr, "releasePduSessionId", e);
+            }
+        } else {
+            AsyncResult.forMessage(result, null,
+                    CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+            result.sendToTarget();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void startHandover(Message result, int callId) {
+        android.hardware.radio.V1_6.IRadio radioProxy16 = getRadioV16(result);
+
+        if (radioProxy16 != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_START_HANDOVER, result,
+                    mRILDefaultWorkSource);
+            if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+            try {
+                radioProxy16.startHandover(rr.mSerial, callId);
+            } catch (RemoteException e) {
+                handleRadioProxyExceptionForRR(rr, "startHandover", e);
+            }
+        } else {
+            if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "startHandover: REQUEST_NOT_SUPPORTED");
+            AsyncResult.forMessage(result, null,
+                    CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+            result.sendToTarget();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void cancelHandover(Message result, int callId) {
+        android.hardware.radio.V1_6.IRadio radioProxy16 = getRadioV16(result);
+
+        if (radioProxy16 != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_CANCEL_HANDOVER, result,
+                    mRILDefaultWorkSource);
+            if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+            try {
+                radioProxy16.cancelHandover(rr.mSerial, callId);
+            } catch (RemoteException e) {
+                handleRadioProxyExceptionForRR(rr, "cancelHandover", e);
+            }
+        } else {
+            if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "cancelHandover: REQUEST_NOT_SUPPORTED");
+            AsyncResult.forMessage(result, null,
+                    CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+            result.sendToTarget();
+        }
+    }
+
     //***** Private Methods
+    /** Helper that gets V1.6 of the radio interface OR sends back REQUEST_NOT_SUPPORTED */
+    @Nullable private android.hardware.radio.V1_6.IRadio getRadioV16(Message msg) {
+        IRadio radioProxy = getRadioProxy(msg);
+        if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_6)) {
+            return (android.hardware.radio.V1_6.IRadio) radioProxy;
+        } else {
+            return (android.hardware.radio.V1_6.IRadio) null;
+        }
+    }
+
 
     /**
      * This is a helper function to be called when a RadioIndication callback is called.
@@ -6544,6 +6652,14 @@
                 return "RIL_REQUEST_ENABLE_NR_DUAL_CONNECTIVITY";
             case RIL_REQUEST_IS_NR_DUAL_CONNECTIVITY_ENABLED:
                 return "RIL_REQUEST_IS_NR_DUAL_CONNECTIVITY_ENABLED";
+            case RIL_REQUEST_ALLOCATE_PDU_SESSION_ID:
+                return "RIL_REQUEST_ALLOCATE_PDU_SESSION_ID";
+            case RIL_REQUEST_RELEASE_PDU_SESSION_ID:
+                return "RIL_REQUEST_RELEASE_PDU_SESSION_ID";
+            case RIL_REQUEST_START_HANDOVER:
+                return "RIL_REQUEST_START_HANDOVER";
+            case RIL_REQUEST_CANCEL_HANDOVER:
+                return "RIL_REQUEST_CANCEL_HANDOVER";
             default: return "<unknown request>";
         }
     }
@@ -7044,6 +7160,8 @@
         @HandoverFailureMode
         int handoverFailureMode = DataCallResponse.HANDOVER_FAILURE_MODE_LEGACY;
 
+        int pduSessionId = DataCallResponse.PDU_SESSION_ID_NOT_SET;
+
         List<LinkAddress> laList = new ArrayList<>();
 
         if (dcResult instanceof android.hardware.radio.V1_0.SetupDataCallResult) {
@@ -7131,6 +7249,7 @@
             mtuV4 = result.mtuV4;
             mtuV6 = result.mtuV6;
             handoverFailureMode = result.handoverFailureMode;
+            pduSessionId = result.pduSessionId;
         } else {
             Rlog.e(RILJ_LOG_TAG, "Unsupported SetupDataCallResult " + dcResult);
             return null;
@@ -7196,6 +7315,7 @@
                 .setMtuV4(mtuV4)
                 .setMtuV6(mtuV6)
                 .setHandoverFailureMode(handoverFailureMode)
+                .setPduSessionId(pduSessionId)
                 .build();
     }
 
diff --git a/src/java/com/android/internal/telephony/RadioResponse.java b/src/java/com/android/internal/telephony/RadioResponse.java
index 6332ef1..dbf8ff3 100644
--- a/src/java/com/android/internal/telephony/RadioResponse.java
+++ b/src/java/com/android/internal/telephony/RadioResponse.java
@@ -37,6 +37,7 @@
 import android.hardware.radio.V1_4.CarrierRestrictionsWithPriority;
 import android.hardware.radio.V1_4.SimLockMultiSimPolicy;
 import android.hardware.radio.V1_6.IRadioResponse;
+import android.hardware.radio.V1_6.SetupDataCallResult;
 import android.os.AsyncResult;
 import android.os.Message;
 import android.os.SystemClock;
@@ -115,7 +116,7 @@
      * @param cardStatus ICC card status as defined by CardStatus in 1.2/types.hal
      */
     public void getIccCardStatusResponse_1_2(RadioResponseInfo responseInfo,
-                                             android.hardware.radio.V1_2.CardStatus cardStatus) {
+            android.hardware.radio.V1_2.CardStatus cardStatus) {
         responseIccCardStatus_1_2(responseInfo, cardStatus);
     }
 
@@ -124,7 +125,7 @@
      * @param cardStatus ICC card status as defined by CardStatus in 1.4/types.hal
      */
     public void getIccCardStatusResponse_1_4(RadioResponseInfo responseInfo,
-                                             android.hardware.radio.V1_4.CardStatus cardStatus) {
+            android.hardware.radio.V1_4.CardStatus cardStatus) {
         responseIccCardStatus_1_4(responseInfo, cardStatus);
     }
 
@@ -190,7 +191,7 @@
      * @param retriesRemaining Number of retries remaining, must be equal to -1 if unknown.
      */
     public void supplyNetworkDepersonalizationResponse(RadioResponseInfo responseInfo,
-                                                       int retriesRemaining) {
+            int retriesRemaining) {
         responseInts(responseInfo, retriesRemaining);
     }
 
@@ -211,7 +212,7 @@
      * @param calls Current call list
      */
     public void getCurrentCallsResponse(RadioResponseInfo responseInfo,
-                                        ArrayList<android.hardware.radio.V1_0.Call> calls) {
+            ArrayList<android.hardware.radio.V1_0.Call> calls) {
         responseCurrentCalls(responseInfo, calls);
     }
 
@@ -220,7 +221,7 @@
      * @param calls Current call list
      */
     public void getCurrentCallsResponse_1_2(RadioResponseInfo responseInfo,
-                                        ArrayList<android.hardware.radio.V1_2.Call> calls) {
+            ArrayList<android.hardware.radio.V1_2.Call> calls) {
         responseCurrentCalls_1_2(responseInfo, calls);
     }
 
@@ -289,12 +290,12 @@
      *        described in the "CDMA IS-2000 Release A (C.S0005-A v6.0)" standard.
      */
     public void getLastCallFailCauseResponse(RadioResponseInfo responseInfo,
-                                             LastCallFailCauseInfo fcInfo) {
+            LastCallFailCauseInfo fcInfo) {
         responseLastCallFailCauseInfo(responseInfo, fcInfo);
     }
 
     public void getSignalStrengthResponse(RadioResponseInfo responseInfo,
-                                          android.hardware.radio.V1_0.SignalStrength sigStrength) {
+            android.hardware.radio.V1_0.SignalStrength sigStrength) {
         responseSignalStrength(responseInfo, sigStrength);
     }
 
@@ -307,7 +308,7 @@
             android.hardware.radio.V1_2.SignalStrength signalStrength) {
         responseSignalStrength_1_2(responseInfo, signalStrength);
     }
-     /**
+    /**
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param signalStrength Current signal strength of camped/connected cells
      */
@@ -323,7 +324,7 @@
      *        in types.hal
      */
     public void getVoiceRegistrationStateResponse(RadioResponseInfo responseInfo,
-                                                  VoiceRegStateResult voiceRegResponse) {
+            VoiceRegStateResult voiceRegResponse) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
@@ -387,7 +388,7 @@
      *        types.hal
      */
     public void getDataRegistrationStateResponse(RadioResponseInfo responseInfo,
-                                                 DataRegStateResult dataRegResponse) {
+            DataRegStateResult dataRegResponse) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
@@ -469,9 +470,9 @@
      * @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) {
+            String longName,
+            String shortName,
+            String numeric) {
         responseStrings(responseInfo, longName, shortName, numeric);
     }
 
@@ -495,7 +496,7 @@
      * @param sms Response to sms sent as defined by SendSmsResult in types.hal
      */
     public void sendSmsResponse(RadioResponseInfo responseInfo,
-                                SendSmsResult sms) {
+            SendSmsResult sms) {
         responseSms(responseInfo, sms);
     }
 
@@ -514,7 +515,7 @@
      * @param sms Response to sms sent as defined by SendSmsResult in types.hal
      */
     public void sendSMSExpectMoreResponse(RadioResponseInfo responseInfo,
-                                          SendSmsResult sms) {
+            SendSmsResult sms) {
         responseSms(responseInfo, sms);
     }
 
@@ -559,12 +560,43 @@
         responseSetupDataCall(responseInfo, setupDataCallResult);
     }
 
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param setupDataCallResult Response to data call setup as defined by setupDataCallResult in
+     *                            1.6/types.hal
+     */
+    public void setupDataCallResponse_1_6(
+            android.hardware.radio.V1_6.RadioResponseInfo responseInfo,
+            android.hardware.radio.V1_6.SetupDataCallResult setupDataCallResult) {
+        responseSetupDataCall_1_6(responseInfo, setupDataCallResult);
+    }
+
+    @Override
+    public void getDataCallListResponse_1_6(android.hardware.radio.V1_6.RadioResponseInfo info,
+            ArrayList<SetupDataCallResult> dcResponse) {
+        responseDataCallList(info, dcResponse);
+    }
+
+    @Override
+    public void setSimCardPowerResponse_1_6(android.hardware.radio.V1_6.RadioResponseInfo info) {
+        /* This method was missing a response, will let the owner know */
+        responseVoid_1_6(info);
+    }
+
+    @Override
+    public void setAllowedNetworkTypeBitmapResponse(
+            android.hardware.radio.V1_6.RadioResponseInfo info) {
+        /* This method was missing a response, will let the owner know */
+        responseVoid_1_6(info);
+    }
+
     /**
      * @param responseInfo Response info struct containing response type, serial no. and error
      * @param iccIo ICC io operation response as defined by IccIoResult in types.hal
      */
     public void iccIOForAppResponse(RadioResponseInfo responseInfo,
-                            android.hardware.radio.V1_0.IccIoResult iccIo) {
+            android.hardware.radio.V1_0.IccIoResult iccIo) {
         responseIccIo(responseInfo, iccIo);
     }
 
@@ -604,8 +636,8 @@
      *        each distinct registered phone number.
      */
     public void getCallForwardStatusResponse(RadioResponseInfo responseInfo,
-                                             ArrayList<android.hardware.radio.V1_0.CallForwardInfo>
-                                                     callForwardInfos) {
+            ArrayList<android.hardware.radio.V1_0.CallForwardInfo>
+                    callForwardInfos) {
         responseCallForwardInfo(responseInfo, callForwardInfos);
     }
 
@@ -627,8 +659,8 @@
      *        and voice and disabled for everything else.
      */
     public void getCallWaitingResponse(RadioResponseInfo responseInfo,
-                                   boolean enable,
-                                   int serviceClass) {
+            boolean enable,
+            int serviceClass) {
         responseInts(responseInfo, enable ? 1 : 0, serviceClass);
     }
 
@@ -724,8 +756,8 @@
      *                     types.hal
      */
     public void getAvailableNetworksResponse(RadioResponseInfo responseInfo,
-                                             ArrayList<android.hardware.radio.V1_0.OperatorInfo>
-                                                     networkInfos) {
+            ArrayList<android.hardware.radio.V1_0.OperatorInfo>
+                    networkInfos) {
         responseOperatorInfos(responseInfo, networkInfos);
     }
 
@@ -850,7 +882,7 @@
     }
 
     public void sendOemRilRequestRawResponse(RadioResponseInfo responseInfo,
-                                             ArrayList<Byte> var2) {}
+            ArrayList<Byte> var2) {}
 
     /**
      * @param responseInfo Response info struct containing response type, serial no. and error
@@ -887,7 +919,7 @@
      * @param bandModes List of RadioBandMode listing supported modes
      */
     public void getAvailableBandModesResponse(RadioResponseInfo responseInfo,
-                                              ArrayList<Integer> bandModes) {
+            ArrayList<Integer> bandModes) {
         responseIntArrayList(responseInfo, bandModes);
     }
 
@@ -968,7 +1000,7 @@
      * @param cells Vector of neighboring radio cell information
      */
     public void getNeighboringCidsResponse(RadioResponseInfo responseInfo,
-                                           ArrayList<NeighboringCell> cells) {
+            ArrayList<NeighboringCell> cells) {
         responseCellList(responseInfo, cells);
     }
 
@@ -1032,7 +1064,7 @@
      *        true for Enhanced Privacy Mode (Private Long Code Mask)
      */
     public void getPreferredVoicePrivacyResponse(RadioResponseInfo responseInfo,
-                                                 boolean enable) {
+            boolean enable) {
         responseInts(responseInfo, enable ? 1 : 0);
     }
 
@@ -1111,7 +1143,7 @@
      * @param configs Vector of GSM/WCDMA Cell broadcast configs
      */
     public void getGsmBroadcastConfigResponse(RadioResponseInfo responseInfo,
-                                              ArrayList<GsmBroadcastSmsConfigInfo> configs) {
+            ArrayList<GsmBroadcastSmsConfigInfo> configs) {
         responseGmsBroadcastConfig(responseInfo, configs);
     }
 
@@ -1135,7 +1167,7 @@
      * @param configs Vector of CDMA Broadcast SMS configs.
      */
     public void getCdmaBroadcastConfigResponse(RadioResponseInfo responseInfo,
-                                               ArrayList<CdmaBroadcastSmsConfigInfo> configs) {
+            ArrayList<CdmaBroadcastSmsConfigInfo> configs) {
         responseCdmaBroadcastConfig(responseInfo, configs);
     }
 
@@ -1165,7 +1197,7 @@
      * @param prl PRL version if CDMA subscription is available
      */
     public void getCDMASubscriptionResponse(RadioResponseInfo responseInfo, String mdn,
-                                            String hSid, String hNid, String min, String prl) {
+            String hSid, String hNid, String min, String prl) {
         responseStrings(responseInfo, mdn, hSid, hNid, min, prl);
     }
 
@@ -1193,7 +1225,7 @@
      * @param meid MEID if CDMA subscription is available
      */
     public void getDeviceIdentityResponse(RadioResponseInfo responseInfo, String imei,
-                                          String imeisv, String esn, String meid) {
+            String imeisv, String esn, String meid) {
         responseStrings(responseInfo, imei, imeisv, esn, meid);
     }
 
@@ -1265,7 +1297,7 @@
      * @param iccIo IccIoResult as defined in types.hal corresponding to ICC IO response
      */
     public void sendEnvelopeWithStatusResponse(RadioResponseInfo responseInfo,
-                                               android.hardware.radio.V1_0.IccIoResult iccIo) {
+            android.hardware.radio.V1_0.IccIoResult iccIo) {
         responseIccIo(responseInfo, iccIo);
     }
 
@@ -1279,7 +1311,7 @@
     }
 
     public void getCellInfoListResponse(RadioResponseInfo responseInfo,
-                                        ArrayList<android.hardware.radio.V1_0.CellInfo> cellInfo) {
+            ArrayList<android.hardware.radio.V1_0.CellInfo> cellInfo) {
         responseCellInfoList(responseInfo, cellInfo);
     }
 
@@ -1342,7 +1374,7 @@
      *        isRegistered is true.
      */
     public void getImsRegistrationStateResponse(RadioResponseInfo responseInfo,
-                                                boolean isRegistered, int ratFamily) {
+            boolean isRegistered, int ratFamily) {
         responseInts(
                 responseInfo,
                 isRegistered ? 1 : 0,
@@ -1366,8 +1398,8 @@
      * @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);
     }
 
@@ -1379,7 +1411,7 @@
      *        byte per integer
      */
     public void iccOpenLogicalChannelResponse(RadioResponseInfo responseInfo, int channelId,
-                                              ArrayList<Byte> selectResponse) {
+            ArrayList<Byte> selectResponse) {
         ArrayList<Integer> arr = new ArrayList<>();
         arr.add(channelId);
         for (int i = 0; i < selectResponse.size(); i++) {
@@ -1462,8 +1494,8 @@
      * @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) {
@@ -1501,7 +1533,7 @@
     }
 
     public void getRadioCapabilityResponse(RadioResponseInfo responseInfo,
-                                           android.hardware.radio.V1_0.RadioCapability rc) {
+            android.hardware.radio.V1_0.RadioCapability rc) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
@@ -1521,7 +1553,7 @@
     }
 
     public void setRadioCapabilityResponse(RadioResponseInfo responseInfo,
-                                           android.hardware.radio.V1_0.RadioCapability rc) {
+            android.hardware.radio.V1_0.RadioCapability rc) {
         responseRadioCapability(responseInfo, rc);
     }
 
@@ -1553,7 +1585,7 @@
      * @param activityInfo modem activity information
      */
     public void getModemActivityInfoResponse(RadioResponseInfo responseInfo,
-                                             ActivityStatsInfo activityInfo) {
+            ActivityStatsInfo activityInfo) {
         responseActivityData(responseInfo, activityInfo);
     }
 
@@ -1578,87 +1610,11 @@
 
     /**
      *
-     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param info Response info struct containing response type, serial no. and error
      */
     public void setNrDualConnectivityStateResponse(
-            android.hardware.radio.V1_6.RadioResponseInfo  responseInfo) {
-        responseVoid_1_6(responseInfo);
-    }
-
-    /**
-     *
-     * @param responseInfo Response info struct containing response type, serial no. and error
-     * @param dcResponse SetupDataCallResult
-     */
-    public void setupDataCallResponse_1_6(
-            android.hardware.radio.V1_6.RadioResponseInfo  responseInfo,
-            android.hardware.radio.V1_6.SetupDataCallResult dcResponse) {
-        responseVoid_1_6(responseInfo);
-    }
-
-    /**
-     *
-     * @param responseInfo Response info struct containing response type, serial no. and error
-     * @param dcResponse List of SetupDataCallResult
-     */
-    public void getDataCallListResponse_1_6(
-            android.hardware.radio.V1_6.RadioResponseInfo  responseInfo,
-            ArrayList<android.hardware.radio.V1_6.SetupDataCallResult> dcResponse) {
-        responseVoid_1_6(responseInfo);
-    }
-
-    /**
-     *
-     * @param responseInfo Response info struct containing response type, serial no. and error
-     * @param id The allocated id. On an error, this is set to -1     */
-    public void allocatePduSessionIdResponse(
-            android.hardware.radio.V1_6.RadioResponseInfo responseInfo, int id) {
-        responseVoid_1_6(responseInfo);
-    }
-
-    /**
-     *
-     * @param responseInfo Response info struct containing response type, serial no. and error
-     */
-    public void releasePduSessionIdResponse(
-            android.hardware.radio.V1_6.RadioResponseInfo responseInfo) {
-        responseVoid_1_6(responseInfo);
-    }
-
-    /**
-     *
-     * @param responseInfo Response info struct containing response type, serial no. and error
-     */
-    public void beginHandoverResponse(
-            android.hardware.radio.V1_6.RadioResponseInfo responseInfo) {
-        responseVoid_1_6(responseInfo);
-    }
-
-    /**
-     *
-     * @param responseInfo Response info struct containing response type, serial no. and error
-     */
-    public void cancelHandoverResponse(
-            android.hardware.radio.V1_6.RadioResponseInfo responseInfo) {
-        responseVoid_1_6(responseInfo);
-    }
-
-    /**
-     *
-     * @param responseInfo Response info struct containing response type, serial no. and error
-     */
-    public void setAllowedNetworkTypeBitmapResponse(
-            android.hardware.radio.V1_6.RadioResponseInfo responseInfo) {
-        responseVoid_1_6(responseInfo);
-    }
-
-    /**
-     *
-     * @param responseInfo Response info struct containing response type, serial no. and error
-     */
-    public void setSimCardPowerResponse_1_6(
-            android.hardware.radio.V1_6.RadioResponseInfo responseInfo) {
-        responseVoid_1_6(responseInfo);
+            android.hardware.radio.V1_6.RadioResponseInfo info) {
+        responseVoid_1_6(info);
     }
 
     /**
@@ -1895,7 +1851,7 @@
         if (numApplications
                 > com.android.internal.telephony.uicc.IccCardStatus.CARD_MAX_APPS) {
             numApplications =
-                com.android.internal.telephony.uicc.IccCardStatus.CARD_MAX_APPS;
+                    com.android.internal.telephony.uicc.IccCardStatus.CARD_MAX_APPS;
         }
         iccCardStatus.mApplications = new IccCardApplicationStatus[numApplications];
         for (int i = 0; i < numApplications; i++) {
@@ -1904,7 +1860,7 @@
             appStatus.app_type       = appStatus.AppTypeFromRILInt(rilAppStatus.appType);
             appStatus.app_state      = appStatus.AppStateFromRILInt(rilAppStatus.appState);
             appStatus.perso_substate = appStatus.PersoSubstateFromRILInt(
-                rilAppStatus.persoSubstate);
+                    rilAppStatus.persoSubstate);
             appStatus.aid            = rilAppStatus.aidPtr;
             appStatus.app_label      = rilAppStatus.appLabelPtr;
             appStatus.pin1_replaced  = rilAppStatus.pin1Replaced;
@@ -1972,7 +1928,7 @@
     }
 
     private void responseIccCardStatus_1_2(RadioResponseInfo responseInfo,
-                                           android.hardware.radio.V1_2.CardStatus cardStatus) {
+            android.hardware.radio.V1_2.CardStatus cardStatus) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
@@ -1989,7 +1945,7 @@
     }
 
     private void responseIccCardStatus_1_4(RadioResponseInfo responseInfo,
-                                           android.hardware.radio.V1_4.CardStatus cardStatus) {
+            android.hardware.radio.V1_4.CardStatus cardStatus) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
@@ -2051,7 +2007,7 @@
     }
 
     private void responseCurrentCalls(RadioResponseInfo responseInfo,
-                                      ArrayList<android.hardware.radio.V1_0.Call> calls) {
+            ArrayList<android.hardware.radio.V1_0.Call> calls) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
@@ -2130,7 +2086,7 @@
     }
 
     private void responseCurrentCalls_1_2(RadioResponseInfo responseInfo,
-                                      ArrayList<android.hardware.radio.V1_2.Call> calls) {
+            ArrayList<android.hardware.radio.V1_2.Call> calls) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
@@ -2255,7 +2211,7 @@
     }
 
     static void responseStringArrayList(RIL ril, RadioResponseInfo responseInfo,
-                                        ArrayList<String> strings) {
+            ArrayList<String> strings) {
         RILRequest rr = ril.processResponse(responseInfo);
 
         if (rr != null) {
@@ -2271,7 +2227,7 @@
     }
 
     private void responseLastCallFailCauseInfo(RadioResponseInfo responseInfo,
-                                               LastCallFailCauseInfo fcInfo) {
+            LastCallFailCauseInfo fcInfo) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
@@ -2355,7 +2311,7 @@
     }
 
     private void responseSetupDataCall(RadioResponseInfo responseInfo,
-                                       Object setupDataCallResult) {
+            Object setupDataCallResult) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
@@ -2367,8 +2323,22 @@
         }
     }
 
+    private void responseSetupDataCall_1_6(
+            android.hardware.radio.V1_6.RadioResponseInfo responseInfo,
+            Object setupDataCallResult) {
+        RILRequest rr = mRil.processResponse_1_6(responseInfo);
+
+        if (rr != null) {
+            DataCallResponse response = RIL.convertDataCallResult(setupDataCallResult);
+            if (responseInfo.error == RadioError.NONE) {
+                sendMessageResponse(rr.mResult, response);
+            }
+            mRil.processResponseDone_1_6(rr, responseInfo, response);
+        }
+    }
+
     private void responseIccIo(RadioResponseInfo responseInfo,
-                               android.hardware.radio.V1_0.IccIoResult result) {
+            android.hardware.radio.V1_0.IccIoResult result) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
@@ -2381,8 +2351,8 @@
     }
 
     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()];
@@ -2417,8 +2387,8 @@
     }
 
     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) {
@@ -2469,7 +2439,7 @@
     }
 
     private void responseDataCallList(RadioResponseInfo responseInfo,
-                                      List<? extends Object> dataCallResultList) {
+            List<? extends Object> dataCallResultList) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
@@ -2482,8 +2452,22 @@
         }
     }
 
+    private void responseDataCallList(android.hardware.radio.V1_6.RadioResponseInfo responseInfo,
+            List<? extends Object> dataCallResultList) {
+        RILRequest rr = mRil.processResponse_1_6(responseInfo);
+
+        if (rr != null) {
+            ArrayList<DataCallResponse> response =
+                    RIL.convertDataCallResultList(dataCallResultList);
+            if (responseInfo.error == RadioError.NONE) {
+                sendMessageResponse(rr.mResult, response);
+            }
+            mRil.processResponseDone_1_6(rr, responseInfo, response);
+        }
+    }
+
     private void responseCellList(RadioResponseInfo responseInfo,
-                                  ArrayList<NeighboringCell> cells) {
+            ArrayList<NeighboringCell> cells) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
@@ -2513,7 +2497,7 @@
     }
 
     private void responseGmsBroadcastConfig(RadioResponseInfo responseInfo,
-                                            ArrayList<GsmBroadcastSmsConfigInfo> configs) {
+            ArrayList<GsmBroadcastSmsConfigInfo> configs) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
@@ -2531,7 +2515,7 @@
     }
 
     private void responseCdmaBroadcastConfig(RadioResponseInfo responseInfo,
-                                            ArrayList<CdmaBroadcastSmsConfigInfo> configs) {
+            ArrayList<CdmaBroadcastSmsConfigInfo> configs) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
@@ -2579,7 +2563,7 @@
     }
 
     private void responseCellInfoList(RadioResponseInfo responseInfo,
-                                      ArrayList<android.hardware.radio.V1_0.CellInfo> cellInfo) {
+            ArrayList<android.hardware.radio.V1_0.CellInfo> cellInfo) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
@@ -2633,7 +2617,7 @@
     }
 
     private void responseActivityData(RadioResponseInfo responseInfo,
-                                      ActivityStatsInfo activityInfo) {
+            ActivityStatsInfo activityInfo) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
@@ -2673,7 +2657,7 @@
     }
 
     private void responseRadioCapability(RadioResponseInfo responseInfo,
-                                         android.hardware.radio.V1_0.RadioCapability rc) {
+            android.hardware.radio.V1_0.RadioCapability rc) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
         if (rr != null) {
@@ -2734,8 +2718,8 @@
     }
 
     private void responseCarrierRestrictions(RadioResponseInfo responseInfo, boolean allAllowed,
-                                            CarrierRestrictionsWithPriority carriers,
-                                            int multiSimPolicy) {
+            CarrierRestrictionsWithPriority carriers,
+            int multiSimPolicy) {
         RILRequest rr = mRil.processResponse(responseInfo);
         if (rr == null) {
             return;
@@ -2867,4 +2851,40 @@
             mRil.processResponseDone(rr, responseInfo, bi);
         }
     }
-}
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param id The pdu session id allocated
+     */
+    public void allocatePduSessionIdResponse(android.hardware.radio.V1_6.RadioResponseInfo info,
+            int id) {
+        RILRequest rr = mRil.processResponse_1_6(info);
+        if (rr != null) {
+            if (info.error == RadioError.NONE) {
+                sendMessageResponse(rr.mResult, id);
+            }
+            mRil.processResponseDone_1_6(rr, info, id);
+        }
+    }
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     */
+    public void releasePduSessionIdResponse(android.hardware.radio.V1_6.RadioResponseInfo info) {
+        responseVoid_1_6(info);
+    }
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     */
+    public void startHandoverResponse(android.hardware.radio.V1_6.RadioResponseInfo info) {
+        responseVoid_1_6(info);
+    }
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     */
+    public void cancelHandoverResponse(android.hardware.radio.V1_6.RadioResponseInfo info) {
+        responseVoid_1_6(info);
+    }
+}
\ No newline at end of file
diff --git a/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java b/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
index a4b5929..520e90c 100644
--- a/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
+++ b/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
@@ -16,6 +16,9 @@
 
 package com.android.internal.telephony.dataconnection;
 
+import static android.telephony.data.DataServiceCallback.RESULT_SUCCESS;
+
+import android.annotation.Nullable;
 import android.net.LinkProperties;
 import android.os.AsyncResult;
 import android.os.Handler;
@@ -27,6 +30,7 @@
 import android.telephony.data.DataService;
 import android.telephony.data.DataServiceCallback;
 
+import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
 import com.android.telephony.Rlog;
@@ -50,6 +54,8 @@
     private static final int SET_DATA_PROFILE_COMPLETE              = 4;
     private static final int REQUEST_DATA_CALL_LIST_COMPLETE        = 5;
     private static final int DATA_CALL_LIST_CHANGED                 = 6;
+    private static final int START_HANDOVER                         = 7;
+    private static final int CANCEL_HANDOVER                        = 8;
 
     private class CellularDataServiceProvider extends DataService.DataServiceProvider {
 
@@ -75,29 +81,29 @@
                             DataCallResponse response = (DataCallResponse) ar.result;
                             callback.onSetupDataCallComplete(ar.exception != null
                                     ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
-                                    : DataServiceCallback.RESULT_SUCCESS,
+                                    : RESULT_SUCCESS,
                                     response);
                             break;
                         case DEACTIVATE_DATA_ALL_COMPLETE:
                             callback.onDeactivateDataCallComplete(ar.exception != null
                                     ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
-                                    : DataServiceCallback.RESULT_SUCCESS);
+                                    : RESULT_SUCCESS);
                             break;
                         case SET_INITIAL_ATTACH_APN_COMPLETE:
                             callback.onSetInitialAttachApnComplete(ar.exception != null
                                     ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
-                                    : DataServiceCallback.RESULT_SUCCESS);
+                                    : RESULT_SUCCESS);
                             break;
                         case SET_DATA_PROFILE_COMPLETE:
                             callback.onSetDataProfileComplete(ar.exception != null
                                     ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
-                                    : DataServiceCallback.RESULT_SUCCESS);
+                                    : RESULT_SUCCESS);
                             break;
                         case REQUEST_DATA_CALL_LIST_COMPLETE:
                             callback.onRequestDataCallListComplete(
                                     ar.exception != null
                                             ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
-                                            : DataServiceCallback.RESULT_SUCCESS,
+                                            : RESULT_SUCCESS,
                                     ar.exception != null
                                             ? null : (List<DataCallResponse>) ar.result
                                     );
@@ -105,9 +111,14 @@
                         case DATA_CALL_LIST_CHANGED:
                             notifyDataCallListChanged((List<DataCallResponse>) ar.result);
                             break;
+                        case START_HANDOVER:
+                            callback.onHandoverStarted(toResultCode(ar.exception));
+                            break;
+                        case CANCEL_HANDOVER:
+                            callback.onHandoverCancelled(toResultCode(ar.exception));
+                            break;
                         default:
                             loge("Unexpected event: " + message.what);
-                            return;
                     }
                 }
             };
@@ -116,10 +127,31 @@
             mPhone.mCi.registerForDataCallListChanged(mHandler, DATA_CALL_LIST_CHANGED, null);
         }
 
+
+        /* Converts the result code for start handover and cancel handover */
+        @DataServiceCallback.ResultCode private int toResultCode(@Nullable Throwable t) {
+            if (t == null) {
+                return RESULT_SUCCESS;
+            } else {
+                if (t instanceof CommandException) {
+                    CommandException ce = (CommandException) t;
+                    if (ce.getCommandError() == CommandException.Error.REQUEST_NOT_SUPPORTED) {
+                        return DataServiceCallback.RESULT_ERROR_UNSUPPORTED;
+                    } else {
+                        return DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE;
+                    }
+                } else {
+                    loge("Throwable is of type " + t.getClass().getSimpleName()
+                            + " but should be CommandException");
+                    return DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE;
+                }
+            }
+        }
+
         @Override
-        public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
-                                  boolean allowRoaming, int reason, LinkProperties linkProperties,
-                                  DataServiceCallback callback) {
+        public void setupDataCall(int accessNetworkType, DataProfile dataProfile,
+                boolean isRoaming, boolean allowRoaming, int reason, LinkProperties linkProperties,
+                int pduSessionId, DataServiceCallback callback) {
             if (DBG) log("setupDataCall " + getSlotIndex());
 
             Message message = null;
@@ -131,7 +163,7 @@
             }
 
             mPhone.mCi.setupDataCall(accessNetworkType, dataProfile, isRoaming, allowRoaming,
-                    reason, linkProperties, message);
+                    reason, linkProperties, pduSessionId, message);
         }
 
         @Override
@@ -196,6 +228,31 @@
         }
 
         @Override
+        public void startHandover(int cid, DataServiceCallback callback) {
+            if (DBG) log("startHandover " + getSlotIndex());
+            Message message = null;
+            // Only obtain the message when the caller wants a callback. If the caller doesn't care
+            // the request completed or results, then no need to pass the message down.
+            if (callback != null) {
+                message = Message.obtain(mHandler, START_HANDOVER);
+                mCallbackMap.put(message, callback);
+            }
+            mPhone.mCi.startHandover(message, cid);
+        }
+
+        @Override
+        public void cancelHandover(int cid, DataServiceCallback callback) {
+            Message message = null;
+            // Only obtain the message when the caller wants a callback. If the caller doesn't care
+            // the request completed or results, then no need to pass the message down.
+            if (callback != null) {
+                message = Message.obtain(mHandler, CANCEL_HANDOVER);
+                mCallbackMap.put(message, callback);
+            }
+            mPhone.mCi.cancelHandover(message, cid);
+        }
+
+        @Override
         public void close() {
             mPhone.mCi.unregisterForDataCallListChanged(mHandler);
         }
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index 6a7f472..d3fd4fb 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -19,7 +19,10 @@
 import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_CONGESTED;
 import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED;
 
+import static com.android.internal.telephony.dataconnection.DcTracker.REQUEST_TYPE_HANDOVER;
+
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -105,6 +108,7 @@
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
 
 /**
  * {@hide}
@@ -273,6 +277,7 @@
     private DataServiceManager mDataServiceManager;
     private final int mTransportType;
     private LinkProperties mLinkProperties = new LinkProperties();
+    private int mPduSessionId;
     private long mCreateTime;
     private long mLastFailTime;
     @DataFailureCause
@@ -343,7 +348,10 @@
     static final int EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED = BASE + 31;
     static final int EVENT_CSS_INDICATOR_CHANGED = BASE + 32;
     static final int EVENT_UPDATE_SUSPENDED_STATE = BASE + 33;
-    private static final int CMD_TO_STRING_COUNT = EVENT_UPDATE_SUSPENDED_STATE - BASE + 1;
+    static final int EVENT_START_HANDOVER = BASE + 34;
+    static final int EVENT_CANCEL_HANDOVER = BASE + 35;
+    static final int EVENT_START_HANDOVER_ON_TARGET = BASE + 36;
+    private static final int CMD_TO_STRING_COUNT = EVENT_START_HANDOVER_ON_TARGET - BASE + 1;
 
     private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
     static {
@@ -389,6 +397,9 @@
                 "EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED";
         sCmdToString[EVENT_CSS_INDICATOR_CHANGED - BASE] = "EVENT_CSS_INDICATOR_CHANGED";
         sCmdToString[EVENT_UPDATE_SUSPENDED_STATE - BASE] = "EVENT_UPDATE_SUSPENDED_STATE";
+        sCmdToString[EVENT_START_HANDOVER - BASE] = "EVENT_START_HANDOVER";
+        sCmdToString[EVENT_CANCEL_HANDOVER - BASE] = "EVENT_CANCEL_HANDOVER";
+        sCmdToString[EVENT_START_HANDOVER_ON_TARGET - BASE] = "EVENT_START_HANDOVER_ON_TARGET";
     }
     // Convert cmd to string or null if unknown
     static String cmdToString(int cmd) {
@@ -573,6 +584,10 @@
         return ret;
     }
 
+    public int getPduSessionId() {
+        return mPduSessionId;
+    }
+
     @VisibleForTesting
     public UpdateLinkPropertyResult updateLinkProperty(DataCallResponse newState) {
         UpdateLinkPropertyResult result = new UpdateLinkPropertyResult(mLinkProperties);
@@ -609,6 +624,14 @@
         return result;
     }
 
+    void setPduSessionId(int pduSessionId) {
+        if (mPduSessionId != pduSessionId) {
+            logd("Changing pdu session id from: " + mPduSessionId + " to: " + pduSessionId + ", "
+                    + "Handover state: " + handoverStateToString(this.mHandoverState));
+            mPduSessionId = pduSessionId;
+        }
+    }
+
     /**
      * Read the MTU value from link properties where it can be set from network. In case
      * not set by the network, set it again using the mtu szie value defined in the APN
@@ -771,42 +794,47 @@
         // Check if this data setup is a handover.
         LinkProperties linkProperties = null;
         int reason = DataService.REQUEST_REASON_NORMAL;
-        if (cp.mRequestType == DcTracker.REQUEST_TYPE_HANDOVER) {
+        if (cp.mRequestType == REQUEST_TYPE_HANDOVER) {
             // If this is a data setup for handover, we need to pass the link properties
             // of the existing data connection to the modem.
-            DcTracker dcTracker = mPhone.getDcTracker(getHandoverSourceTransport());
-            if (dcTracker == null || cp.mApnContext == null) {
-                loge("connect: Handover failed. dcTracker=" + dcTracker + ", apnContext="
+            DcTracker srcDcTracker = mPhone.getDcTracker(getHandoverSourceTransport());
+            if (srcDcTracker == null || cp.mApnContext == null) {
+                loge("connect: Handover failed. dcTracker=" + srcDcTracker + ", apnContext="
                         + cp.mApnContext);
                 return DataFailCause.HANDOVER_FAILED;
             }
 
-            DataConnection dc = dcTracker.getDataConnectionByApnType(cp.mApnContext.getApnType());
-            if (dc == null) {
+
+            // srcDc is the source data connection while the current instance is the target
+            DataConnection srcDc =
+                    srcDcTracker.getDataConnectionByApnType(cp.mApnContext.getApnType());
+            if (srcDc == null) {
                 loge("connect: Can't find data connection for handover.");
                 return DataFailCause.HANDOVER_FAILED;
             }
 
-            // Preserve the potential network agent from the source data connection. The ownership
-            // is not transferred at this moment.
-            mHandoverSourceNetworkAgent = dc.getNetworkAgent();
-            if (mHandoverSourceNetworkAgent == null) {
-                loge("Cannot get network agent from the source dc " + dc.getName());
-                return DataFailCause.HANDOVER_FAILED;
-            }
+            // Helpful for logging purposes
+            DataServiceManager srcDsm = srcDc.mDataServiceManager;
+            String srcDsmTag = (srcDsm == null ? "(null)" : srcDsm.getTag());
+            logd("connect: REQUEST_TYPE_HANDOVER - Request handover from " + srcDc.getName()
+                    + ", targetDsm=" + mDataServiceManager.getTag()
+                    + ", sourceDsm=" + srcDsmTag);
 
-            linkProperties = dc.getLinkProperties();
-            if (linkProperties == null || linkProperties.getLinkAddresses().isEmpty()) {
-                loge("connect: Can't find link properties of handover data connection. dc="
-                        + dc);
-                return DataFailCause.HANDOVER_FAILED;
-            }
 
-            mHandoverLocalLog.log("Handover started. Preserved the agent.");
-            log("Get the handover source network agent: " + mHandoverSourceNetworkAgent);
-
-            dc.setHandoverState(HANDOVER_STATE_BEING_TRANSFERRED);
-            reason = DataService.REQUEST_REASON_HANDOVER;
+            /* startHandover is called on the source data connection, and if successful,
+               we ask the target data connection (which is the current instance) to call
+               #setupDataCall with request type handover.
+            */
+            Consumer<Integer> onCompleted = (dataServiceCallbackResultCode) ->
+                    /* startHandover is called on the srcDc handler, but the callback needs to
+                       be called on the current (which is the targetDc) handler which is why we
+                       call sendRunnableMessage. */
+                    sendRunnableMessage(EVENT_START_HANDOVER_ON_TARGET,
+                        (inCorrectState) -> requestHandover(inCorrectState, srcDc,
+                            dataServiceCallbackResultCode,
+                            cp, msg, dp, isModemRoaming, allowRoaming));
+            srcDc.startHandover(onCompleted);
+            return DataFailCause.NONE;
         }
 
         mDataServiceManager.setupDataCall(
@@ -816,12 +844,129 @@
                 allowRoaming,
                 reason,
                 linkProperties,
+                DataCallResponse.PDU_SESSION_ID_NOT_SET,
                 msg);
         TelephonyMetrics.getInstance().writeSetupDataCall(mPhone.getPhoneId(), cp.mRilRat,
                 dp.getProfileId(), dp.getApn(), dp.getProtocolType());
         return DataFailCause.NONE;
     }
 
+    private void requestHandover(boolean inCorrectState, DataConnection srcDc,
+            @DataServiceCallback.ResultCode int resultCode,
+            ConnectionParams cp, Message msg, DataProfile dp, boolean isModemRoaming,
+            boolean allowRoaming) {
+
+        if (!inCorrectState) {
+            logd("requestHandover: Not in correct state");
+            if (isResultCodeSuccess(resultCode)) {
+                if (srcDc != null) {
+                    logd("requestHandover: Not in correct state - Success result code");
+                    // We need to cancel the handover on source if we ended up in the wrong state.
+                    srcDc.cancelHandover();
+                } else {
+                    logd("requestHandover: Not in correct state - Success result code - "
+                            + "srcdc = null");
+                }
+            }
+            notifyConnectCompleted(cp, DataFailCause.UNKNOWN,
+                    DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, false);
+            return;
+        } else if (!isResultCodeSuccess(resultCode)) {
+            if (DBG) {
+                logd("requestHandover: Non success result code from DataService, "
+                        + "setupDataCall will not be called, result code = "
+                        + DataServiceCallback.resultCodeToString(resultCode));
+            }
+            notifyConnectCompleted(cp, DataFailCause.UNKNOWN,
+                    DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, false);
+            return;
+        }
+
+        if (srcDc == null) {
+            return;
+        }
+
+        LinkProperties linkProperties;
+        int reason;
+
+        // Preserve the potential network agent from the source data connection. The ownership
+        // is not transferred at this moment.
+        mHandoverSourceNetworkAgent = srcDc.getNetworkAgent();
+        if (mHandoverSourceNetworkAgent == null) {
+            loge("requestHandover: Cannot get network agent from the source dc " + srcDc.getName());
+            notifyConnectCompleted(cp, DataFailCause.UNKNOWN,
+                    DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, false);
+            return;
+        }
+
+        linkProperties = srcDc.getLinkProperties();
+        if (linkProperties == null || linkProperties.getLinkAddresses().isEmpty()) {
+            loge("requestHandover: Can't find link properties of handover data connection. dc="
+                    + srcDc);
+            notifyConnectCompleted(cp, DataFailCause.UNKNOWN,
+                    DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, false);
+            return;
+        }
+
+        mHandoverLocalLog.log("Handover started. Preserved the agent.");
+        log("Get the handover source network agent: " + mHandoverSourceNetworkAgent);
+
+        reason = DataService.REQUEST_REASON_HANDOVER;
+
+        mDataServiceManager.setupDataCall(
+                ServiceState.rilRadioTechnologyToAccessNetworkType(cp.mRilRat),
+                dp,
+                isModemRoaming,
+                allowRoaming,
+                reason,
+                linkProperties,
+                srcDc.getPduSessionId(),
+                msg);
+        TelephonyMetrics.getInstance().writeSetupDataCall(mPhone.getPhoneId(), cp.mRilRat,
+                dp.getProfileId(), dp.getApn(), dp.getProtocolType());
+    }
+
+    /**
+     * Called on the source data connection from the target data connection.
+     */
+    private void startHandover(Consumer<Integer> onTargetDcComplete) {
+        logd("startHandover: " + toStringSimple());
+        // Set the handover state to being transferred on "this" data connection which is the src.
+        setHandoverState(HANDOVER_STATE_BEING_TRANSFERRED);
+
+        Consumer<Integer> onSrcDcComplete =
+                resultCode -> onHandoverStarted(resultCode, onTargetDcComplete);
+        /*
+            The flow here is:
+            srcDc#startHandover -> dataService#startHandover -> (onHandoverStarted) ->
+                onSrcDcComplete -> onTargetDcComplete
+         */
+        mDataServiceManager.startHandover(mCid,
+                this.obtainMessage(EVENT_START_HANDOVER,
+                        onSrcDcComplete));
+    }
+
+    /**
+     * Called on the source data connection when the async call to start handover is complete
+     */
+    private void onHandoverStarted(@DataServiceCallback.ResultCode int resultCode,
+            Consumer<Integer> onTargetDcComplete) {
+        logd("onHandoverStarted: " + toStringSimple());
+        if (!isResultCodeSuccess(resultCode)) {
+            setHandoverState(HANDOVER_STATE_IDLE);
+        }
+        onTargetDcComplete.accept(resultCode);
+    }
+
+    private void cancelHandover() {
+        if (mHandoverState != HANDOVER_STATE_BEING_TRANSFERRED) {
+            logd("cancelHandover: handover state is " + handoverStateToString(mHandoverState)
+                    + ", expecting HANDOVER_STATE_BEING_TRANSFERRED");
+        }
+        mDataServiceManager.cancelHandover(mCid, this.obtainMessage(EVENT_CANCEL_HANDOVER));
+        setHandoverState(HANDOVER_STATE_IDLE);
+    }
+
     public void onSubscriptionOverride(int overrideMask, int overrideValue) {
         mSubscriptionOverride = (mSubscriptionOverride & ~overrideMask)
                 | (overrideValue & overrideMask);
@@ -959,6 +1104,10 @@
         if (DBG) log("NotifyDisconnectCompleted DisconnectParams=" + dp);
     }
 
+    private void sendRunnableMessage(int eventCode, @NonNull final Consumer<Boolean> r) {
+        sendMessage(eventCode, r);
+    }
+
     /*
      * **************************************************************************
      * Begin Members and methods owned by DataConnectionTracker but stored
@@ -1048,12 +1197,20 @@
             if (DBG) log("onSetupConnectionCompleted received successful DataCallResponse");
             mCid = response.getId();
             updatePcscfAddr(response);
+
             result = updateLinkProperty(response).setupResult;
+
+            setPduSessionId(response.getPduSessionId());
         }
 
         return result;
     }
 
+    private static boolean isResultCodeSuccess(int resultCode) {
+        return resultCode == DataServiceCallback.RESULT_SUCCESS
+                || resultCode == DataServiceCallback.RESULT_ERROR_UNSUPPORTED;
+    }
+
     private boolean isDnsOk(String[] domainNameServers) {
         if (NULL_IP.equals(domainNameServers[0]) && NULL_IP.equals(domainNameServers[1])
                 && !mPhone.isDnsCheckDisabled()) {
@@ -1817,6 +1974,29 @@
                                 + " mRilRat=" + mRilRat);
                     }
                     break;
+
+                case EVENT_START_HANDOVER:  //calls startHandover()
+                    if (DBG) {
+                        log("DcDefaultState: EVENT_START_HANDOVER not expected.");
+                    }
+                    Consumer<Integer> r = (Consumer<Integer>) msg.obj;
+                    r.accept(DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE);
+                    break;
+                case EVENT_START_HANDOVER_ON_TARGET:
+                    if (DBG) {
+                        log("DcDefaultState: EVENT_START_HANDOVER not expected, but will "
+                                + "clean up, result code: "
+                                + DataServiceCallback.resultCodeToString(msg.arg1));
+                    }
+                    ((Consumer<Boolean>) msg.obj).accept(false /* is in correct state*/);
+                    break;
+                case EVENT_CANCEL_HANDOVER:
+                    // We don't need to do anything in this case
+                    if (DBG) {
+                        log("DcDefaultState: EVENT_CANCEL_HANDOVER resultCode="
+                                + DataServiceCallback.resultCodeToString(msg.arg1));
+                    }
+                    break;
                 default:
                     if (DBG) {
                         log("DcDefaultState: ignore msg.what=" + getWhatToString(msg.what));
@@ -1907,7 +2087,7 @@
                     mHandoverLocalLog.log(
                             "Handover failed. Reset the source dc " + sourceDc.getName()
                                     + " state to idle");
-                    sourceDc.setHandoverState(HANDOVER_STATE_IDLE);
+                    sourceDc.cancelHandover();
                 } else {
                     // The agent is now a dangling agent. No data connection owns this agent.
                     // Gracefully notify connectivity service disconnected.
@@ -1927,7 +2107,8 @@
                     log("DcInactiveState: enter notifyConnectCompleted +ALL failCause="
                             + mDcFailCause);
                 }
-                notifyConnectCompleted(mConnectionParams, mDcFailCause, mHandoverFailureMode, true);
+                notifyConnectCompleted(mConnectionParams, mDcFailCause, mHandoverFailureMode,
+                        true);
             }
             if (mDisconnectParams != null) {
                 if (DBG) {
@@ -2148,6 +2329,11 @@
                     mAdministratorUids = Arrays.copyOf(administratorUids, administratorUids.length);
                     retVal = HANDLED;
                     break;
+                case EVENT_START_HANDOVER_ON_TARGET:
+                    //called after startHandover on target transport
+                    ((Consumer<Boolean>) msg.obj).accept(true /* is in correct state*/);
+                    retVal = HANDLED;
+                    break;
                 default:
                     if (VDBG) {
                         log("DcActivatingState not handled msg.what=" +
@@ -2219,7 +2405,7 @@
             }
 
             if (mConnectionParams != null
-                    && mConnectionParams.mRequestType == DcTracker.REQUEST_TYPE_HANDOVER) {
+                    && mConnectionParams.mRequestType == REQUEST_TYPE_HANDOVER) {
                 // If this is a data setup for handover, we need to reuse the existing network agent
                 // instead of creating a new one. This should be transparent to connectivity
                 // service.
@@ -2657,6 +2843,11 @@
                     }
                     retVal = HANDLED;
                     break;
+                case EVENT_START_HANDOVER:  //calls startHandover()
+                    Consumer<Integer> r = (Consumer<Integer>) msg.obj;
+                    r.accept(msg.arg1);
+                    retVal = HANDLED;
+                    break;
                 default:
                     if (VDBG) {
                         log("DcActiveState not handled msg.what=" + getWhatToString(msg.what));
@@ -2952,8 +3143,10 @@
 
     void setHandoverState(@HandoverState int state) {
         if (mHandoverState != state) {
-            mHandoverLocalLog.log("State changed from " + handoverStateToString(mHandoverState)
-                    + " to " + handoverStateToString(state));
+            String logStr = "State changed from " + handoverStateToString(mHandoverState)
+                    + " to " + handoverStateToString(state);
+            mHandoverLocalLog.log(logStr);
+            logd(logStr);
             mHandoverState = state;
         }
     }
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java b/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java
index 78f0e02..0b4bc0a 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java
@@ -20,6 +20,7 @@
 import static android.text.format.DateUtils.SECOND_IN_MILLIS;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -108,6 +109,16 @@
 
     private CellularDataServiceConnection mServiceConnection;
 
+    /**
+     * Helpful for logging
+     * @return the tag name
+     *
+     * @hide
+     */
+    public String getTag() {
+        return mTag;
+    }
+
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -290,6 +301,20 @@
             mDataCallListChangedRegistrants.notifyRegistrants(
                     new AsyncResult(null, dataCallList, null));
         }
+
+        @Override
+        public void onHandoverStarted(@DataServiceCallback.ResultCode int resultCode) {
+            if (DBG) log("onHandoverStarted. resultCode = " + resultCode);
+            Message msg = mMessageMap.remove(asBinder());
+            sendCompleteMessage(msg, resultCode);
+        }
+
+        @Override
+        public void onHandoverCancelled(@DataServiceCallback.ResultCode int resultCode) {
+            if (DBG) log("onHandoverCancelled. resultCode = " + resultCode);
+            Message msg = mMessageMap.remove(asBinder());
+            sendCompleteMessage(msg, resultCode);
+        }
     }
 
     /**
@@ -551,7 +576,7 @@
         return className;
     }
 
-    private void sendCompleteMessage(Message msg, int code) {
+    private void sendCompleteMessage(Message msg, @DataServiceCallback.ResultCode int code) {
         if (msg != null) {
             msg.arg1 = code;
             msg.sendToTarget();
@@ -572,15 +597,18 @@
      *        {@link DataService#REQUEST_REASON_HANDOVER}.
      * @param linkProperties If {@code reason} is {@link DataService#REQUEST_REASON_HANDOVER}, this
      *        is the link properties of the existing data connection, otherwise null.
+     * @param pduSessionId The pdu session id to be used for this data call.  A value of -1 means
+     *                     no pdu session id was attached to this call.
+     *                     Reference: 3GPP TS 24.007 section 11.2.3.1b
      * @param onCompleteMessage The result message for this request. Null if the client does not
      *        care about the result.
      */
     public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
                               boolean allowRoaming, int reason, LinkProperties linkProperties,
-                              Message onCompleteMessage) {
+                              int pduSessionId, Message onCompleteMessage) {
         if (DBG) log("setupDataCall");
         if (!mBound) {
-            loge("Data service not bound.");
+            loge("setupDataCall: Data service not bound.");
             sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE);
             return;
         }
@@ -593,9 +621,9 @@
             sendMessageDelayed(obtainMessage(EVENT_WATCHDOG_TIMEOUT, callback),
                     REQUEST_UNRESPONDED_TIMEOUT);
             mIDataService.setupDataCall(mPhone.getPhoneId(), accessNetworkType, dataProfile,
-                    isRoaming, allowRoaming, reason, linkProperties, callback);
+                    isRoaming, allowRoaming, reason, linkProperties, pduSessionId, callback);
         } catch (RemoteException e) {
-            loge("Cannot invoke setupDataCall on data service.");
+            loge("setupDataCall: Cannot invoke setupDataCall on data service.");
             mMessageMap.remove(callback.asBinder());
             sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE);
         }
@@ -639,6 +667,91 @@
     }
 
     /**
+     * Indicates that a handover has begun.  This is called on the source transport.
+     *
+     * Any resources being transferred cannot be released while a
+     * handover is underway.
+     *
+     * If a handover was unsuccessful, then the framework calls DataServiceManager#cancelHandover.
+     * The target transport retains ownership over any of the resources being transferred.
+     *
+     * If a handover was successful, the framework calls DataServiceManager#deactivateDataCall with
+     * reason HANDOVER. The target transport now owns the transferred resources and is
+     * responsible for releasing them.
+     *
+     * @param cid The identifier of the data call which is provided in DataCallResponse
+     * @param onCompleteMessage The result callback for this request.
+     */
+    public void startHandover(int cid, @NonNull Message onCompleteMessage) {
+        CellularDataServiceCallback callback =
+                setupCallbackHelper("startHandover", onCompleteMessage);
+        if (callback == null) {
+            loge("startHandover: callback == null");
+            sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE);
+            return;
+        }
+
+        try {
+            sendMessageDelayed(obtainMessage(EVENT_WATCHDOG_TIMEOUT, callback),
+                    REQUEST_UNRESPONDED_TIMEOUT);
+            mIDataService.startHandover(mPhone.getPhoneId(), cid, callback);
+        } catch (RemoteException e) {
+            loge("Cannot invoke startHandover on data service.");
+            mMessageMap.remove(callback.asBinder());
+            sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE);
+        }
+    }
+
+    /**
+     * Indicates that a handover was cancelled after a call to DataServiceManager#startHandover.
+     * This is called on the source transport.
+     *
+     * Since the handover was unsuccessful, the source transport retains ownership over any of
+     * the resources being transferred and is still responsible for releasing them.
+     *
+     * @param cid The identifier of the data call which is provided in DataCallResponse
+     * @param onCompleteMessage The result callback for this request.
+     */
+    public void cancelHandover(int cid, @NonNull Message onCompleteMessage) {
+        CellularDataServiceCallback callback =
+                setupCallbackHelper("cancelHandover", onCompleteMessage);
+        if (callback == null) {
+            sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE);
+            return;
+        }
+
+        try {
+            sendMessageDelayed(obtainMessage(EVENT_WATCHDOG_TIMEOUT, callback),
+                    REQUEST_UNRESPONDED_TIMEOUT);
+            mIDataService.cancelHandover(mPhone.getPhoneId(), cid, callback);
+        } catch (RemoteException e) {
+            loge("Cannot invoke cancelHandover on data service.");
+            mMessageMap.remove(callback.asBinder());
+            sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE);
+        }
+    }
+
+    @Nullable
+    private CellularDataServiceCallback setupCallbackHelper(
+            @NonNull final String operationName, @NonNull final Message onCompleteMessage) {
+        if (DBG) log(operationName);
+        if (!mBound) {
+            sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE);
+            return null;
+        }
+
+        CellularDataServiceCallback callback =
+                new CellularDataServiceCallback(operationName);
+        if (onCompleteMessage != null) {
+            if (DBG) log(operationName + ": onCompleteMessage set");
+            mMessageMap.put(callback.asBinder(), onCompleteMessage);
+        } else {
+            if (DBG) log(operationName + ": onCompleteMessage not set");
+        }
+        return callback;
+    }
+
+    /**
      * Set an APN to initial attach network.
      *
      * @param dataProfile Data profile used for data call setup. See {@link DataProfile}.
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcController.java b/src/java/com/android/internal/telephony/dataconnection/DcController.java
index 3505453..59dafca 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcController.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcController.java
@@ -296,7 +296,11 @@
                         }
                     }
                 } else {
+                    // Update the pdu session id
+                    dc.setPduSessionId(newState.getPduSessionId());
+
                     dc.updatePcscfAddr(newState);
+
                     // Its active so update the DataConnections link properties
                     UpdateLinkPropertyResult result = dc.updateLinkProperty(newState);
                     if (result.oldLp.equals(result.newLp)) {
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
index 9dcb06f..e9cf8b0 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
@@ -31,9 +31,9 @@
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.RadioCapability;
 import com.android.internal.telephony.UUSInfo;
-import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState;
 import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo;
 import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
+import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState;
 
 /**
  * Volte doesn't need CommandsInterface. The class does nothing but made to work
@@ -283,7 +283,7 @@
     @Override
     public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
                               boolean allowRoaming, int reason, LinkProperties linkProperties,
-                              Message result) {
+                              int pduSessionId, Message result) {
     }
 
     @Override
@@ -663,4 +663,20 @@
     @Override
     public void stopNattKeepalive(int sessionHandle, Message result) {
     }
+
+    @Override
+    public void allocatePduSessionId(Message result) {
+    }
+
+    @Override
+    public void releasePduSessionId(Message result, int pduSessionId) {
+    }
+
+    @Override
+    public void startHandover(Message result, int callId) {
+    }
+
+    @Override
+    public void cancelHandover(Message result, int callId) {
+    }
 }
diff --git a/src/java/com/android/internal/telephony/sip/SipCommandInterface.java b/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
index e57c12f..e4dfae7 100644
--- a/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
+++ b/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
@@ -30,9 +30,9 @@
 import com.android.internal.telephony.BaseCommands;
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.UUSInfo;
-import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState;
 import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo;
 import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
+import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState;
 
 /**
  * SIP doesn't need CommandsInterface. The class does nothing but made to work
@@ -284,7 +284,7 @@
     @Override
     public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
                               boolean allowRoaming, int reason, LinkProperties linkProperties,
-                              Message result) {
+                              int pduSessionId, Message result) {
     }
 
     @Override
@@ -663,4 +663,20 @@
     @Override
     public void stopNattKeepalive(int sessionHandle, Message result) {
     }
+
+    @Override
+    public void allocatePduSessionId(Message result) {
+    }
+
+    @Override
+    public void releasePduSessionId(Message result, int pduSessionId) {
+    }
+
+    @Override
+    public void startHandover(Message result, int callId) {
+    }
+
+    @Override
+    public void cancelHandover(Message result, int callId) {
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
index d74b5ff..cc693b8 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
@@ -2505,7 +2505,8 @@
                 .build();
 
         mRILUnderTest.setupDataCall(AccessNetworkConstants.AccessNetworkType.EUTRAN, dp, false,
-                false, 0, null, obtainMessage());
+                false, 0, null,
+                DataCallResponse.PDU_SESSION_ID_NOT_SET, obtainMessage());
         ArgumentCaptor<DataProfileInfo> dpiCaptor = ArgumentCaptor.forClass(DataProfileInfo.class);
         verify(mRadioProxy).setupDataCall(
                 mSerialNumberCaptor.capture(), eq(AccessNetworkConstants.AccessNetworkType.EUTRAN),
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java
index 029812d..e231599 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java
@@ -1177,10 +1177,10 @@
     @Override
     public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
                               boolean allowRoaming, int reason, LinkProperties linkProperties,
-                              Message result) {
+                              int pduSessionId, Message result) {
 
         SimulatedCommandsVerifier.getInstance().setupDataCall(accessNetworkType, dataProfile,
-                isRoaming, allowRoaming, reason, linkProperties, result);
+                isRoaming, allowRoaming, reason, linkProperties, pduSessionId, result);
 
         if (mSetupDataCallResult == null) {
             try {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
index 314ae28..632e13f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
@@ -31,9 +31,9 @@
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.RadioCapability;
 import com.android.internal.telephony.UUSInfo;
-import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState;
 import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo;
 import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
+import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState;
 
 public class SimulatedCommandsVerifier implements CommandsInterface {
     private static SimulatedCommandsVerifier sInstance;
@@ -1181,7 +1181,7 @@
     @Override
     public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
                               boolean allowRoaming, int reason, LinkProperties linkProperties,
-                              Message result) {
+                              int pduSessionId, Message result) {
     }
 
     @Override
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
index 2939ff5..68a8fc5 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
@@ -385,7 +385,8 @@
         ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
                 eq(AccessNetworkType.UTRAN), dpCaptor.capture(), eq(false),
-                eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), any(Message.class));
+                eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
+                anyInt(), any(Message.class));
 
         assertEquals("spmode.ne.jp", dpCaptor.getValue().getApn());
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
index a3f2e72..6b0cda0 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
@@ -691,7 +691,7 @@
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), any(DataProfile.class),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
     }
 
     // Test the normal data call setup scenario.
@@ -720,7 +720,7 @@
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
 
         verifyDataConnected(FAKE_APN1);
@@ -762,7 +762,7 @@
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
 
         // This time we'll let RIL command succeed.
@@ -781,7 +781,7 @@
         verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN2, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
 
         // Verify connected with APN2 setting.
@@ -806,7 +806,7 @@
         verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, NETWORK_TYPE_LTE_BITMASK);
 
         logd("Sending DATA_DISABLED_CMD");
@@ -842,7 +842,7 @@
         verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
 
 
         List<DataProfile> dataProfiles = dpCaptor.getAllValues();
@@ -888,7 +888,7 @@
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
         assertEquals(DctConstants.State.IDLE, mDct.getState(PhoneConstants.APN_TYPE_DEFAULT));
         assertEquals(DctConstants.State.CONNECTED, mDct.getState(PhoneConstants.APN_TYPE_MMS));
     }
@@ -918,7 +918,7 @@
         verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
 
         //user is in roaming
@@ -969,7 +969,7 @@
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN3, 2, 64, 0, 0);
 
         assertTrue(mDct.isAnyDataConnected());
@@ -1018,7 +1018,7 @@
         verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, NETWORK_TYPE_LTE_BITMASK);
         assertTrue(mDct.isAnyDataConnected());
 
@@ -1066,7 +1066,7 @@
 
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false),
-                eq(DataService.REQUEST_REASON_NORMAL), any(), any(Message.class));
+                eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(Message.class));
     }
 
     // Test the XCAP APN setup.
@@ -1080,7 +1080,7 @@
 
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false),
-                eq(DataService.REQUEST_REASON_NORMAL), any(), any(Message.class));
+                eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(Message.class));
     }
 
     @Test
@@ -1119,7 +1119,7 @@
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), any(DataProfile.class),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
     }
 
     // Test the unmetered default APN setup when data is disabled. Default APN should always honor
@@ -1141,7 +1141,7 @@
         verify(mSimulatedCommandsVerifier, never()).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), any(DataProfile.class),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
     }
 
 
@@ -1162,7 +1162,7 @@
 
         verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
     }
 
     // Test the restricted data request when data is disabled.
@@ -1189,7 +1189,7 @@
         waitForMs(200);
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(anyInt(), any(DataProfile.class),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
     }
 
     // Test the restricted data request when roaming is disabled.
@@ -1217,7 +1217,7 @@
         waitForMs(200);
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(anyInt(), any(DataProfile.class),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
     }
 
     // Test the default data when data is not connectable.
@@ -1234,7 +1234,7 @@
 
         verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
     }
 
     // Test the default data on IWLAN.
@@ -1257,7 +1257,7 @@
 
         verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
     }
 
     // Test the default data when the phone is in ECBM.
@@ -1274,7 +1274,7 @@
 
         verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
     }
 
     // Test update waiting apn list when on data rat change
@@ -1301,7 +1301,7 @@
         verify(mSimulatedCommandsVerifier).setupDataCall(
                 eq(AccessNetworkType.CDMA2000), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN4, 0, 21, 2, NETWORK_TYPE_EHRPD_BITMASK);
         assertTrue(mDct.isAnyDataConnected());
 
@@ -1338,7 +1338,7 @@
         verify(mSimulatedCommandsVerifier).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
         assertTrue(mDct.isAnyDataConnected());
     }
@@ -1516,7 +1516,7 @@
         verify(mSimulatedCommandsVerifier).setupDataCall(
                 eq(AccessNetworkType.CDMA2000), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN4, 0, 21, 2, NETWORK_TYPE_EHRPD_BITMASK);
         assertTrue(mDct.isAnyDataConnected());
 
@@ -1642,7 +1642,7 @@
         verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
 
         logd("Sending EVENT_NETWORK_STATUS_CHANGED");
@@ -1681,7 +1681,7 @@
         verify(mSimulatedCommandsVerifier, timeout(TEST_TIMEOUT).times(2)).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
         waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
 
@@ -1722,7 +1722,7 @@
         verify(mSimulatedCommandsVerifier, timeout(TEST_TIMEOUT).times(2)).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
 
         logd("Sending EVENT_NETWORK_STATUS_CHANGED false");
@@ -1760,7 +1760,7 @@
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
 
         logd("Sending EVENT_NETWORK_STATUS_CHANGED false");
@@ -1793,7 +1793,7 @@
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
 
         logd("Sending EVENT_NETWORK_STATUS_CHANGED false");
@@ -2146,7 +2146,7 @@
         verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
                 eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
                 eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
-                any(Message.class));
+                anyInt(), any(Message.class));
         verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
 
         verifyDataConnected(FAKE_APN1);