Merge "Fix ImsService Callback synchronization issues"
diff --git a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
index abf91c9..59fdd0f 100644
--- a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
@@ -324,6 +324,7 @@
         public Notification.Builder getNotificationBuilder() {
             Context context = mPhone.getContext();
             Intent notificationIntent = new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS);
+            notificationIntent.putExtra("expandable", true);
             PendingIntent settingsIntent = PendingIntent.getActivity(context, 0, notificationIntent,
                     PendingIntent.FLAG_ONE_SHOT);
             CharSequence title = context.getText(
diff --git a/src/java/com/android/internal/telephony/IccCard.java b/src/java/com/android/internal/telephony/IccCard.java
index 7e98bc9..bef6afc 100644
--- a/src/java/com/android/internal/telephony/IccCard.java
+++ b/src/java/com/android/internal/telephony/IccCard.java
@@ -34,8 +34,8 @@
  * Apps (those that have access to Phone object) can retrieve this object
  * by calling phone.getIccCard()
  *
- * This interface is implemented by IccCardProxy and the object PhoneApp
- * gets when it calls getIccCard is IccCardProxy.
+ * This interface is implemented by UiccProfile and the object PhoneApp
+ * gets when it calls getIccCard is UiccProfile.
  */
 public interface IccCard {
     /**
diff --git a/src/java/com/android/internal/telephony/RatRatcheter.java b/src/java/com/android/internal/telephony/RatRatcheter.java
index e6032a5..5e2850d 100644
--- a/src/java/com/android/internal/telephony/RatRatcheter.java
+++ b/src/java/com/android/internal/telephony/RatRatcheter.java
@@ -22,11 +22,12 @@
 import android.os.PersistableBundle;
 import android.os.UserHandle;
 import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
 import android.telephony.ServiceState;
+import android.telephony.Rlog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 
 /**
@@ -48,6 +49,8 @@
     private final SparseArray<SparseIntArray> mRatFamilyMap = new SparseArray<>();
 
     private final Phone mPhone;
+    private boolean mVoiceRatchetEnabled = true;
+    private boolean mDataRatchetEnabled = true;
 
     /**
      * Updates the ServiceState with a new set of cell bandwidths IFF the new bandwidth list has a
@@ -98,22 +101,37 @@
     }
 
     /** Ratchets RATs and cell bandwidths if oldSS and newSS have the same RAT family. */
-    public void ratchet(ServiceState oldSS, ServiceState newSS) {
-        int newVoiceRat = ratchetRat(oldSS.getRilVoiceRadioTechnology(),
-                newSS.getRilVoiceRadioTechnology());
-        int newDataRat = ratchetRat(oldSS.getRilDataRadioTechnology(),
-                newSS.getRilDataRadioTechnology());
-
+    public void ratchet(ServiceState oldSS, ServiceState newSS, boolean locationChange) {
         if (isSameRatFamily(oldSS, newSS)) {
             updateBandwidths(oldSS.getCellBandwidths(), newSS);
         }
+        // temporarily disable rat ratchet on location change.
+        if (locationChange) {
+            mVoiceRatchetEnabled = false;
+            mDataRatchetEnabled = false;
+            return;
+        }
+        if (mVoiceRatchetEnabled) {
+            int newVoiceRat = ratchetRat(oldSS.getRilVoiceRadioTechnology(),
+                    newSS.getRilVoiceRadioTechnology());
+            newSS.setRilVoiceRadioTechnology(newVoiceRat);
+        } else if (oldSS.getRilVoiceRadioTechnology() != newSS.getRilVoiceRadioTechnology()) {
+            // resume rat ratchet on following rat change within the same location
+            mVoiceRatchetEnabled = true;
+        }
+
+        if (mDataRatchetEnabled) {
+            int newDataRat = ratchetRat(oldSS.getRilDataRadioTechnology(),
+                    newSS.getRilDataRadioTechnology());
+            newSS.setRilDataRadioTechnology(newDataRat);
+        } else if (oldSS.getRilVoiceRadioTechnology() != newSS.getRilVoiceRadioTechnology()) {
+            // resume rat ratchet on following rat change within the same location
+            mVoiceRatchetEnabled = true;
+        }
 
         boolean newUsingCA = oldSS.isUsingCarrierAggregation()
                 || newSS.isUsingCarrierAggregation()
                 || newSS.getCellBandwidths().length > 1;
-
-        newSS.setRilVoiceRadioTechnology(newVoiceRat);
-        newSS.setRilDataRadioTechnology(newDataRat);
         newSS.setIsUsingCarrierAggregation(newUsingCA);
     }
 
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index 9c5b558..dbc06e3 100644
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -139,7 +139,8 @@
      * and ignore stale responses.  The value is a count-down of
      * expected responses in this pollingContext.
      */
-    private int[] mPollingContext;
+    @VisibleForTesting
+    public int[] mPollingContext;
     private boolean mDesiredPowerState;
 
     /**
@@ -2655,8 +2656,8 @@
         // ratchet the new tech up through its rat family but don't drop back down
         // until cell change or device is OOS
         boolean isDataInService = mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE;
-        if (!hasLocationChanged && isDataInService) {
-            mRatRatcheter.ratchet(mSS, mNewSS);
+        if (isDataInService) {
+            mRatRatcheter.ratchet(mSS, mNewSS, hasLocationChanged);
         }
 
         boolean hasRilVoiceRadioTechnologyChanged =
diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
index e379a69..d996fb3 100644
--- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
+++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
@@ -29,7 +29,6 @@
 import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
 import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
-import com.android.internal.telephony.uicc.IccCardProxy;
 import com.android.internal.telephony.uicc.IccCardStatus;
 import com.android.internal.telephony.uicc.UiccCard;
 import com.android.internal.telephony.uicc.UiccProfile;
@@ -100,10 +99,6 @@
         return new IccSmsInterfaceManager(phone);
     }
 
-    public IccCardProxy makeIccCardProxy(Context context, CommandsInterface ci, int phoneId) {
-        return new IccCardProxy(context, ci, phoneId);
-    }
-
     /**
      * Create a new UiccProfile object.
      */
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index 8a101b7..496336f 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -39,6 +39,7 @@
 import android.os.Message;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.telephony.AccessNetworkConstants;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
@@ -1838,10 +1839,26 @@
                     KeepalivePacketData pkt = (KeepalivePacketData) msg.obj;
                     int slotId = msg.arg1;
                     int intervalMillis = msg.arg2 * 1000;
-                    mPhone.mCi.startNattKeepalive(
-                            DataConnection.this.mCid, pkt, intervalMillis,
-                            DataConnection.this.obtainMessage(
-                                    EVENT_KEEPALIVE_STARTED, slotId, 0, null));
+                    if (mDataServiceManager.getTransportType()
+                            == AccessNetworkConstants.TransportType.WWAN) {
+                        mPhone.mCi.startNattKeepalive(
+                                DataConnection.this.mCid, pkt, intervalMillis,
+                                DataConnection.this.obtainMessage(
+                                        EVENT_KEEPALIVE_STARTED, slotId, 0, null));
+                    } else {
+                        // We currently do not support NATT Keepalive requests using the
+                        // DataService API, so unless the request is WWAN (always bound via
+                        // the CommandsInterface), the request cannot be honored.
+                        //
+                        // TODO: b/72331356 to add support for Keepalive to the DataService
+                        // so that keepalive requests can be handled (if supported) by the
+                        // underlying transport.
+                        if (mNetworkAgent != null) {
+                            mNetworkAgent.onPacketKeepaliveEvent(
+                                    msg.arg1,
+                                    ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
+                        }
+                    }
                     retVal = HANDLED;
                     break;
                 }
diff --git a/src/java/com/android/internal/telephony/uicc/IccCardProxy.java b/src/java/com/android/internal/telephony/uicc/IccCardProxy.java
deleted file mode 100644
index f9629e7..0000000
--- a/src/java/com/android/internal/telephony/uicc/IccCardProxy.java
+++ /dev/null
@@ -1,778 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.uicc;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.Intent;
-import android.os.AsyncResult;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Registrant;
-import android.os.RegistrantList;
-import android.os.UserHandle;
-import android.telephony.Rlog;
-import android.telephony.ServiceState;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-
-import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.CommandsInterface.RadioState;
-import com.android.internal.telephony.IccCard;
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.IccCardConstants.State;
-import com.android.internal.telephony.MccTable;
-import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.RILConstants;
-import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
-import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState;
-import com.android.internal.telephony.uicc.IccCardStatus.CardState;
-import com.android.internal.telephony.uicc.IccCardStatus.PinState;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * @Deprecated use {@link UiccController}.getUiccCard instead.
- *
- * The Phone App assumes that there is only one icc card, and one icc application
- * available at a time. Moreover, it assumes such object (represented with IccCard)
- * is available all the time (whether {@link RILConstants#RIL_REQUEST_GET_SIM_STATUS} returned
- * or not, whether card has desired application or not, whether there really is a card in the
- * slot or not).
- *
- * UiccController, however, can handle multiple instances of icc objects (multiple
- * {@link UiccCardApplication}, multiple {@link IccFileHandler}, multiple {@link IccRecords})
- * created and destroyed dynamically during phone operation.
- *
- * This class implements the IccCard interface that is always available (right after default
- * phone object is constructed) to expose the current (based on voice radio technology)
- * application on the uicc card, so that external apps won't break.
- */
-
-public class IccCardProxy extends Handler implements IccCard {
-    private static final boolean DBG = true;
-    private static final String LOG_TAG = "IccCardProxy";
-
-    private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 1;
-    private static final int EVENT_RADIO_ON = 2;
-    private static final int EVENT_ICC_CHANGED = 3;
-    private static final int EVENT_ICC_ABSENT = 4;
-    private static final int EVENT_ICC_LOCKED = 5;
-    private static final int EVENT_APP_READY = 6;
-    private static final int EVENT_RECORDS_LOADED = 7;
-    private static final int EVENT_IMSI_READY = 8;
-    private static final int EVENT_NETWORK_LOCKED = 9;
-
-    private static final int EVENT_ICC_RECORD_EVENTS = 500;
-    private static final int EVENT_CARRIER_PRIVILEGES_LOADED = 503;
-
-    private Integer mPhoneId = null;
-
-    private final Object mLock = new Object();
-    private Context mContext;
-    private CommandsInterface mCi;
-    private TelephonyManager mTelephonyManager;
-
-    private RegistrantList mNetworkLockedRegistrants = new RegistrantList();
-
-    private int mCurrentAppType = UiccController.APP_FAM_3GPP; //default to 3gpp?
-    private UiccController mUiccController = null;
-    private UiccSlot mUiccSlot = null;
-    private UiccCard mUiccCard = null;
-    private UiccCardApplication mUiccApplication = null;
-    private IccRecords mIccRecords = null;
-    private RadioState mRadioState = RadioState.RADIO_UNAVAILABLE;
-    private boolean mInitialized = false;
-    private State mExternalState = State.UNKNOWN;
-
-    public static final String ACTION_INTERNAL_SIM_STATE_CHANGED = "android.intent.action.internal_sim_state_changed";
-
-    public IccCardProxy(Context context, CommandsInterface ci, int phoneId) {
-        if (DBG) log("ctor: ci=" + ci + " phoneId=" + phoneId);
-        mContext = context;
-        mCi = ci;
-        mPhoneId = phoneId;
-        mTelephonyManager = (TelephonyManager) mContext.getSystemService(
-                Context.TELEPHONY_SERVICE);
-        mUiccController = UiccController.getInstance();
-        mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
-        ci.registerForOn(this,EVENT_RADIO_ON, null);
-        ci.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_UNAVAILABLE, null);
-
-        resetProperties();
-    }
-
-    public void dispose() {
-        synchronized (mLock) {
-            log("Disposing");
-            //Cleanup icc references
-            mUiccController.unregisterForIccChanged(this);
-            mUiccController = null;
-            mCi.unregisterForOn(this);
-            mCi.unregisterForOffOrNotAvailable(this);
-        }
-    }
-
-    /*
-     * The card application that the external world sees will be based on the
-     * voice radio technology only!
-     */
-    public void setVoiceRadioTech(int radioTech) {
-        synchronized (mLock) {
-            if (DBG) {
-                log("Setting radio tech " + ServiceState.rilRadioTechnologyToString(radioTech));
-            }
-            if (ServiceState.isGsm(radioTech)) {
-                mCurrentAppType = UiccController.APP_FAM_3GPP;
-            } else {
-                mCurrentAppType = UiccController.APP_FAM_3GPP2;
-            }
-            updateCurrentAppType();
-        }
-    }
-
-    /**
-     * Update current app type and post EVENT_ICC_CHANGED.
-     */
-    private void updateCurrentAppType() {
-        synchronized (mLock) {
-            boolean isLteOnCdmaMode = TelephonyManager.getLteOnCdmaModeStatic()
-                    == PhoneConstants.LTE_ON_CDMA_TRUE;
-            if (mCurrentAppType == UiccController.APP_FAM_3GPP2) {
-                if (isLteOnCdmaMode) {
-                    log("updateCurrentAppType: is cdma/lte device, force IccCardProxy into 3gpp"
-                            + " mode");
-                    mCurrentAppType = UiccController.APP_FAM_3GPP;
-                }
-
-                if (DBG) {
-                    log("updateCurrentAppType: "
-                            + " mCurrentAppType=" + mCurrentAppType
-                            + " isLteOnCdmaMode=" + isLteOnCdmaMode);
-                }
-            }
-
-            mInitialized = true;
-            sendMessage(obtainMessage(EVENT_ICC_CHANGED));
-        }
-    }
-
-    @Override
-    public void handleMessage(Message msg) {
-        switch (msg.what) {
-            case EVENT_RADIO_OFF_OR_UNAVAILABLE:
-                mRadioState = mCi.getRadioState();
-                updateExternalState();
-                break;
-            case EVENT_RADIO_ON:
-                mRadioState = RadioState.RADIO_ON;
-                if (!mInitialized) {
-                    updateCurrentAppType();
-                } else {
-                    // updateCurrentAppType() triggers ICC_CHANGED, which eventually
-                    // calls updateExternalState; thus, we don't need this in the
-                    // above case
-                    updateExternalState();
-                }
-                break;
-            case EVENT_ICC_CHANGED:
-                if (mInitialized) {
-                    updateIccAvailability();
-                }
-                break;
-            case EVENT_ICC_ABSENT:
-                setExternalState(State.ABSENT);
-                break;
-            case EVENT_ICC_LOCKED:
-                processLockedState();
-                break;
-            case EVENT_APP_READY:
-                setExternalState(State.READY);
-                break;
-            case EVENT_RECORDS_LOADED:
-                // Update the MCC/MNC.
-                if (mIccRecords != null) {
-                    String operator = mIccRecords.getOperatorNumeric();
-                    log("operator=" + operator + " mPhoneId=" + mPhoneId);
-
-                    if (!TextUtils.isEmpty(operator)) {
-                        mTelephonyManager.setSimOperatorNumericForPhone(mPhoneId, operator);
-                        String countryCode = operator.substring(0,3);
-                        if (countryCode != null) {
-                            mTelephonyManager.setSimCountryIsoForPhone(mPhoneId,
-                                    MccTable.countryCodeForMcc(Integer.parseInt(countryCode)));
-                        } else {
-                            loge("EVENT_RECORDS_LOADED Country code is null");
-                        }
-                    } else {
-                        loge("EVENT_RECORDS_LOADED Operator name is null");
-                    }
-                }
-                if (mUiccCard != null && !mUiccCard.areCarrierPriviligeRulesLoaded()) {
-                    mUiccCard.registerForCarrierPrivilegeRulesLoaded(
-                            this, EVENT_CARRIER_PRIVILEGES_LOADED, null);
-                } else {
-                    setExternalState(State.LOADED);
-                }
-                break;
-            case EVENT_IMSI_READY:
-                broadcastInternalIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_IMSI,
-                        null);
-                break;
-            case EVENT_NETWORK_LOCKED:
-                mNetworkLockedRegistrants.notifyRegistrants();
-                setExternalState(State.NETWORK_LOCKED);
-                break;
-            case EVENT_ICC_RECORD_EVENTS:
-                if ((mCurrentAppType == UiccController.APP_FAM_3GPP) && (mIccRecords != null)) {
-                    AsyncResult ar = (AsyncResult)msg.obj;
-                    int eventCode = (Integer) ar.result;
-                    if (eventCode == SIMRecords.EVENT_SPN) {
-                        mTelephonyManager.setSimOperatorNameForPhone(
-                                mPhoneId, mIccRecords.getServiceProviderName());
-                    }
-                }
-                break;
-
-            case EVENT_CARRIER_PRIVILEGES_LOADED:
-                log("EVENT_CARRIER_PRIVILEGES_LOADED");
-                if (mUiccCard != null) {
-                    mUiccCard.unregisterForCarrierPrivilegeRulesLoaded(this);
-                }
-                setExternalState(State.LOADED);
-                break;
-
-            default:
-                loge("Unhandled message with number: " + msg.what);
-                break;
-        }
-    }
-
-    private void updateIccAvailability() {
-        synchronized (mLock) {
-            UiccSlot newSlot = mUiccController.getUiccSlotForPhone(mPhoneId);
-            UiccCard newCard = mUiccController.getUiccCard(mPhoneId);
-            UiccCardApplication newApp = null;
-            IccRecords newRecords = null;
-            if (newCard != null) {
-                newApp = newCard.getApplication(mCurrentAppType);
-                if (newApp != null) {
-                    newRecords = newApp.getIccRecords();
-                }
-            }
-
-            if (mIccRecords != newRecords || mUiccApplication != newApp || mUiccCard != newCard
-                    || mUiccSlot != newSlot) {
-                if (DBG) log("Icc changed. Reregistering.");
-                unregisterUiccCardEvents();
-                mUiccSlot = newSlot;
-                mUiccCard = newCard;
-                mUiccApplication = newApp;
-                mIccRecords = newRecords;
-                registerUiccCardEvents();
-            }
-            updateExternalState();
-        }
-    }
-
-    void resetProperties() {
-        if (mCurrentAppType == UiccController.APP_FAM_3GPP) {
-            log("update icc_operator_numeric=" + "");
-            mTelephonyManager.setSimOperatorNumericForPhone(mPhoneId, "");
-            mTelephonyManager.setSimCountryIsoForPhone(mPhoneId, "");
-            mTelephonyManager.setSimOperatorNameForPhone(mPhoneId, "");
-         }
-    }
-
-    private void HandleDetectedState() {
-    // CAF_MSIM SAND
-//        setExternalState(State.DETECTED, false);
-    }
-
-    private void updateExternalState() {
-
-        // mUiccCard could be null at bootup, before valid card states have
-        // been received from UiccController.
-        if (mUiccCard == null) {
-            setExternalState(State.UNKNOWN);
-            return;
-        }
-
-        if (mUiccCard.getCardState() == CardState.CARDSTATE_ABSENT) {
-            /*
-             * Both IccCardProxy and UiccController are registered for
-             * RadioState changes. When the UiccController receives a radio
-             * state changed to Unknown it will dispose of all of the IccCard
-             * objects, which will then notify the IccCardProxy and the null
-             * object will force the state to unknown. However, because the
-             * IccCardProxy is also registered for RadioState changes, it will
-             * recieve that signal first. By triggering on radio state changes
-             * directly, we reduce the time window during which the modem is
-             * UNAVAILABLE but the IccStatus is reported as something valid.
-             * This is not ideal.
-             */
-            if (mRadioState == RadioState.RADIO_UNAVAILABLE) {
-                setExternalState(State.UNKNOWN);
-            } else {
-                setExternalState(State.ABSENT);
-            }
-            return;
-        }
-
-        if (mUiccCard.getCardState() == CardState.CARDSTATE_ERROR) {
-            setExternalState(State.CARD_IO_ERROR);
-            return;
-        }
-
-        if (mUiccCard.getCardState() == CardState.CARDSTATE_RESTRICTED) {
-            setExternalState(State.CARD_RESTRICTED);
-            return;
-        }
-
-        if (mUiccApplication == null) {
-            setExternalState(State.NOT_READY);
-            return;
-        }
-
-        // By process of elimination, the UICC Card State = PRESENT
-        switch (mUiccApplication.getState()) {
-            case APPSTATE_UNKNOWN:
-                /*
-                 * APPSTATE_UNKNOWN is a catch-all state reported whenever the app
-                 * is not explicitly in one of the other states. To differentiate the
-                 * case where we know that there is a card present, but the APP is not
-                 * ready, we choose NOT_READY here instead of unknown. This is possible
-                 * in at least two cases:
-                 * 1) A transient during the process of the SIM bringup
-                 * 2) There is no valid App on the SIM to load, which can be the case with an
-                 *    eSIM/soft SIM.
-                 */
-                setExternalState(State.NOT_READY);
-                break;
-            case APPSTATE_DETECTED:
-                HandleDetectedState();
-                break;
-            case APPSTATE_SUBSCRIPTION_PERSO:
-                if (mUiccApplication.getPersoSubState() ==
-                        PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
-                    setExternalState(State.NETWORK_LOCKED);
-                }
-                // Otherwise don't change external SIM state.
-                break;
-            case APPSTATE_READY:
-                setExternalState(State.READY);
-                break;
-        }
-    }
-
-    private void registerUiccCardEvents() {
-        if (mUiccApplication != null) {
-            mUiccApplication.registerForReady(this, EVENT_APP_READY, null);
-        }
-        if (mIccRecords != null) {
-            mIccRecords.registerForImsiReady(this, EVENT_IMSI_READY, null);
-            mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
-            mIccRecords.registerForLockedRecordsLoaded(this, EVENT_ICC_LOCKED, null);
-            mIccRecords.registerForNetworkLockedRecordsLoaded(this, EVENT_NETWORK_LOCKED, null);
-            mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
-        }
-    }
-
-    private void unregisterUiccCardEvents() {
-        if (mUiccCard != null) mUiccCard.unregisterForCarrierPrivilegeRulesLoaded(this);
-        if (mUiccApplication != null) {
-            mUiccApplication.unregisterForReady(this);
-        }
-        if (mIccRecords != null) {
-            mIccRecords.unregisterForImsiReady(this);
-            mIccRecords.unregisterForRecordsLoaded(this);
-            mIccRecords.unregisterForLockedRecordsLoaded(this);
-            mIccRecords.unregisterForNetworkLockedRecordsLoaded(this);
-            mIccRecords.unregisterForRecordsEvents(this);
-        }
-    }
-
-    private void broadcastInternalIccStateChangedIntent(String value, String reason) {
-        synchronized (mLock) {
-            if (mPhoneId == null) {
-                loge("broadcastInternalIccStateChangedIntent: Card Index is not set; Return!!");
-                return;
-            }
-
-            Intent intent = new Intent(ACTION_INTERNAL_SIM_STATE_CHANGED);
-            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
-                    | Intent.FLAG_RECEIVER_FOREGROUND);
-            intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
-            intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
-            intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
-            intent.putExtra(PhoneConstants.PHONE_KEY, mPhoneId);  // SubId may not be valid.
-            log("broadcastInternalIccStateChangedIntent: Sending intent "
-                    + "ACTION_INTERNAL_SIM_STATE_CHANGED value = " + value
-                    + " for mPhoneId : " + mPhoneId);
-            ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
-        }
-    }
-
-    private void setExternalState(State newState, boolean override) {
-        synchronized (mLock) {
-            if (mPhoneId == null || !SubscriptionManager.isValidSlotIndex(mPhoneId)) {
-                loge("setExternalState: mPhoneId=" + mPhoneId + " is invalid; Return!!");
-                return;
-            }
-
-            if (!override && newState == mExternalState) {
-                log("setExternalState: !override and newstate unchanged from " + newState);
-                return;
-            }
-            mExternalState = newState;
-            log("setExternalState: set mPhoneId=" + mPhoneId + " mExternalState=" + mExternalState);
-            mTelephonyManager.setSimStateForPhone(mPhoneId, getState().toString());
-
-            broadcastInternalIccStateChangedIntent(getIccStateIntentString(mExternalState),
-                    getIccStateReason(mExternalState));
-        }
-    }
-
-    private void processLockedState() {
-        synchronized (mLock) {
-            if (mUiccApplication == null) {
-                //Don't need to do anything if non-existent application is locked
-                return;
-            }
-            PinState pin1State = mUiccApplication.getPin1State();
-            if (pin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) {
-                setExternalState(State.PERM_DISABLED);
-                return;
-            }
-
-            AppState appState = mUiccApplication.getState();
-            switch (appState) {
-                case APPSTATE_PIN:
-                    setExternalState(State.PIN_REQUIRED);
-                    break;
-                case APPSTATE_PUK:
-                    setExternalState(State.PUK_REQUIRED);
-                    break;
-                case APPSTATE_DETECTED:
-                case APPSTATE_READY:
-                case APPSTATE_SUBSCRIPTION_PERSO:
-                case APPSTATE_UNKNOWN:
-                    // Neither required
-                    break;
-            }
-        }
-    }
-
-    private void setExternalState(State newState) {
-        setExternalState(newState, false);
-    }
-
-    public boolean getIccRecordsLoaded() {
-        synchronized (mLock) {
-            if (mIccRecords != null) {
-                return mIccRecords.getRecordsLoaded();
-            }
-            return false;
-        }
-    }
-
-    private String getIccStateIntentString(State state) {
-        switch (state) {
-            case ABSENT: return IccCardConstants.INTENT_VALUE_ICC_ABSENT;
-            case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
-            case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
-            case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
-            case READY: return IccCardConstants.INTENT_VALUE_ICC_READY;
-            case NOT_READY: return IccCardConstants.INTENT_VALUE_ICC_NOT_READY;
-            case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
-            case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR;
-            case CARD_RESTRICTED: return IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED;
-            case LOADED: return IccCardConstants.INTENT_VALUE_ICC_LOADED;
-            default: return IccCardConstants.INTENT_VALUE_ICC_UNKNOWN;
-        }
-    }
-
-    /**
-     * Locked state have a reason (PIN, PUK, NETWORK, PERM_DISABLED, CARD_IO_ERROR)
-     * @return reason
-     */
-    private String getIccStateReason(State state) {
-        switch (state) {
-            case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN;
-            case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK;
-            case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_LOCKED_NETWORK;
-            case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED;
-            case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR;
-            case CARD_RESTRICTED: return IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED;
-            default: return null;
-       }
-    }
-
-    /* IccCard interface implementation */
-    @Override
-    public State getState() {
-        synchronized (mLock) {
-            return mExternalState;
-        }
-    }
-
-    @Override
-    public IccRecords getIccRecords() {
-        synchronized (mLock) {
-            return mIccRecords;
-        }
-    }
-
-    /**
-     * Notifies handler of any transition into State.NETWORK_LOCKED
-     */
-    @Override
-    public void registerForNetworkLocked(Handler h, int what, Object obj) {
-        synchronized (mLock) {
-            Registrant r = new Registrant (h, what, obj);
-
-            mNetworkLockedRegistrants.add(r);
-
-            if (getState() == State.NETWORK_LOCKED) {
-                r.notifyRegistrant();
-            }
-        }
-    }
-
-    @Override
-    public void unregisterForNetworkLocked(Handler h) {
-        synchronized (mLock) {
-            mNetworkLockedRegistrants.remove(h);
-        }
-    }
-
-    @Override
-    public void supplyPin(String pin, Message onComplete) {
-        synchronized (mLock) {
-            if (mUiccApplication != null) {
-                mUiccApplication.supplyPin(pin, onComplete);
-            } else if (onComplete != null) {
-                Exception e = new RuntimeException("ICC card is absent.");
-                AsyncResult.forMessage(onComplete).exception = e;
-                onComplete.sendToTarget();
-                return;
-            }
-        }
-    }
-
-    @Override
-    public void supplyPuk(String puk, String newPin, Message onComplete) {
-        synchronized (mLock) {
-            if (mUiccApplication != null) {
-                mUiccApplication.supplyPuk(puk, newPin, onComplete);
-            } else if (onComplete != null) {
-                Exception e = new RuntimeException("ICC card is absent.");
-                AsyncResult.forMessage(onComplete).exception = e;
-                onComplete.sendToTarget();
-                return;
-            }
-        }
-    }
-
-    @Override
-    public void supplyPin2(String pin2, Message onComplete) {
-        synchronized (mLock) {
-            if (mUiccApplication != null) {
-                mUiccApplication.supplyPin2(pin2, onComplete);
-            } else if (onComplete != null) {
-                Exception e = new RuntimeException("ICC card is absent.");
-                AsyncResult.forMessage(onComplete).exception = e;
-                onComplete.sendToTarget();
-                return;
-            }
-        }
-    }
-
-    @Override
-    public void supplyPuk2(String puk2, String newPin2, Message onComplete) {
-        synchronized (mLock) {
-            if (mUiccApplication != null) {
-                mUiccApplication.supplyPuk2(puk2, newPin2, onComplete);
-            } else if (onComplete != null) {
-                Exception e = new RuntimeException("ICC card is absent.");
-                AsyncResult.forMessage(onComplete).exception = e;
-                onComplete.sendToTarget();
-                return;
-            }
-        }
-    }
-
-    @Override
-    public void supplyNetworkDepersonalization(String pin, Message onComplete) {
-        synchronized (mLock) {
-            if (mUiccApplication != null) {
-                mUiccApplication.supplyNetworkDepersonalization(pin, onComplete);
-            } else if (onComplete != null) {
-                Exception e = new RuntimeException("CommandsInterface is not set.");
-                AsyncResult.forMessage(onComplete).exception = e;
-                onComplete.sendToTarget();
-                return;
-            }
-        }
-    }
-
-    @Override
-    public boolean getIccLockEnabled() {
-        synchronized (mLock) {
-            /* defaults to false, if ICC is absent/deactivated */
-            Boolean retValue = mUiccApplication != null ?
-                    mUiccApplication.getIccLockEnabled() : false;
-            return retValue;
-        }
-    }
-
-    @Override
-    public boolean getIccFdnEnabled() {
-        synchronized (mLock) {
-            Boolean retValue = mUiccApplication != null ?
-                    mUiccApplication.getIccFdnEnabled() : false;
-            return retValue;
-        }
-    }
-
-    public boolean getIccPin2Blocked() {
-        /* defaults to disabled */
-        Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccPin2Blocked() : false;
-        return retValue;
-    }
-
-    public boolean getIccPuk2Blocked() {
-        /* defaults to disabled */
-        Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccPuk2Blocked() : false;
-        return retValue;
-    }
-
-    @Override
-    public void setIccLockEnabled(boolean enabled, String password, Message onComplete) {
-        synchronized (mLock) {
-            if (mUiccApplication != null) {
-                mUiccApplication.setIccLockEnabled(enabled, password, onComplete);
-            } else if (onComplete != null) {
-                Exception e = new RuntimeException("ICC card is absent.");
-                AsyncResult.forMessage(onComplete).exception = e;
-                onComplete.sendToTarget();
-                return;
-            }
-        }
-    }
-
-    @Override
-    public void setIccFdnEnabled(boolean enabled, String password, Message onComplete) {
-        synchronized (mLock) {
-            if (mUiccApplication != null) {
-                mUiccApplication.setIccFdnEnabled(enabled, password, onComplete);
-            } else if (onComplete != null) {
-                Exception e = new RuntimeException("ICC card is absent.");
-                AsyncResult.forMessage(onComplete).exception = e;
-                onComplete.sendToTarget();
-                return;
-            }
-        }
-    }
-
-    @Override
-    public void changeIccLockPassword(String oldPassword, String newPassword, Message onComplete) {
-        synchronized (mLock) {
-            if (mUiccApplication != null) {
-                mUiccApplication.changeIccLockPassword(oldPassword, newPassword, onComplete);
-            } else if (onComplete != null) {
-                Exception e = new RuntimeException("ICC card is absent.");
-                AsyncResult.forMessage(onComplete).exception = e;
-                onComplete.sendToTarget();
-                return;
-            }
-        }
-    }
-
-    @Override
-    public void changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete) {
-        synchronized (mLock) {
-            if (mUiccApplication != null) {
-                mUiccApplication.changeIccFdnPassword(oldPassword, newPassword, onComplete);
-            } else if (onComplete != null) {
-                Exception e = new RuntimeException("ICC card is absent.");
-                AsyncResult.forMessage(onComplete).exception = e;
-                onComplete.sendToTarget();
-                return;
-            }
-        }
-    }
-
-    @Override
-    public String getServiceProviderName() {
-        synchronized (mLock) {
-            if (mIccRecords != null) {
-                return mIccRecords.getServiceProviderName();
-            }
-            return null;
-        }
-    }
-
-    @Override
-    public boolean isApplicationOnIcc(IccCardApplicationStatus.AppType type) {
-        synchronized (mLock) {
-            Boolean retValue = mUiccCard != null ? mUiccCard.isApplicationOnIcc(type) : false;
-            return retValue;
-        }
-    }
-
-    @Override
-    public boolean hasIccCard() {
-        synchronized (mLock) {
-            if (mUiccCard != null && mUiccCard.getCardState() != CardState.CARDSTATE_ABSENT) {
-                return true;
-            }
-            return false;
-        }
-    }
-
-    private void log(String s) {
-        Rlog.d(LOG_TAG, s);
-    }
-
-    private void loge(String msg) {
-        Rlog.e(LOG_TAG, msg);
-    }
-
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println("IccCardProxy: " + this);
-        pw.println(" mContext=" + mContext);
-        pw.println(" mCi=" + mCi);
-        pw.println(" mNetworkLockedRegistrants: size=" + mNetworkLockedRegistrants.size());
-        for (int i = 0; i < mNetworkLockedRegistrants.size(); i++) {
-            pw.println("  mNetworkLockedRegistrants[" + i + "]="
-                    + ((Registrant)mNetworkLockedRegistrants.get(i)).getHandler());
-        }
-        pw.println(" mCurrentAppType=" + mCurrentAppType);
-        pw.println(" mUiccController=" + mUiccController);
-        pw.println(" mUiccCard=" + mUiccCard);
-        pw.println(" mUiccApplication=" + mUiccApplication);
-        pw.println(" mIccRecords=" + mIccRecords);
-        pw.println(" mRadioState=" + mRadioState);
-        pw.println(" mInitialized=" + mInitialized);
-        pw.println(" mExternalState=" + mExternalState);
-
-        pw.flush();
-    }
-}
diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java
index 8e3fb96..a217c34 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java
@@ -198,6 +198,10 @@
         }
     }
 
+    public boolean isExtendedApduSupported() {
+        return  (mAtr != null && mAtr.isExtendedApduSupported());
+    }
+
     @Override
     protected void finalize() {
         if (DBG) log("UiccSlot finalized");
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
index 74aec16..ac116ad 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
@@ -158,6 +158,10 @@
         mBundle.putStringArray(
                 CarrierConfigManager.KEY_NON_ROAMING_OPERATOR_STRING_ARRAY, new String[]{"123456"});
 
+        mBundle.putStringArray(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES,
+                // UMTS < GPRS < EDGE
+                new String[]{"3,1,2"});
+
         mSimulatedCommands.setVoiceRegState(NetworkRegistrationState.REG_STATE_HOME);
         mSimulatedCommands.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_HSPA);
         mSimulatedCommands.setDataRegState(NetworkRegistrationState.REG_STATE_HOME);
@@ -1330,4 +1334,130 @@
             assertTrue(actualNitzSignal.mElapsedRealtime <= SystemClock.elapsedRealtime());
         }
     }
+
+    // Edge and GPRS are grouped under the same family and Edge has higher rate than GPRS.
+    // Expect no rat update when move from E to G.
+    @Test
+    public void testRatRatchet() throws Exception {
+        CellIdentityGsm cellIdentity = new CellIdentityGsm(-1, -1, -1, -1, -1, -1);
+        NetworkRegistrationState dataResult = new NetworkRegistrationState(
+                0, 0, 1, 2, 0, false, null, cellIdentity, 1);
+        sst.mPollingContext[0] = 2;
+        // update data reg state to be in service
+        sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_GPRS,
+                new AsyncResult(sst.mPollingContext, dataResult, null)));
+        waitForMs(200);
+        assertEquals(ServiceState.STATE_IN_SERVICE, mSST.getCurrentDataConnectionState());
+
+        NetworkRegistrationState voiceResult = new NetworkRegistrationState(
+                0, 0, 1, 2, 0, false, null, cellIdentity, false, 0, 0, 0);
+        sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_REGISTRATION,
+                new AsyncResult(sst.mPollingContext, voiceResult, null)));
+        waitForMs(200);
+        assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_EDGE, sst.mSS.getRilVoiceRadioTechnology());
+
+        // EDGE -> GPRS
+        voiceResult = new NetworkRegistrationState(
+                0, 0, 1, 1, 0, false, null,
+                cellIdentity, false, 0, 0, 0);
+        sst.mPollingContext[0] = 2;
+        sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_GPRS,
+                new AsyncResult(sst.mPollingContext, dataResult, null)));
+        waitForMs(200);
+        assertEquals(ServiceState.STATE_IN_SERVICE, mSST.getCurrentDataConnectionState());
+
+        sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_REGISTRATION,
+                new AsyncResult(sst.mPollingContext, voiceResult, null)));
+        waitForMs(200);
+        assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_EDGE, sst.mSS.getRilVoiceRadioTechnology());
+    }
+
+    // Edge and GPRS are grouped under the same family and Edge has higher rate than GPRS.
+    // Bypass rat rachet when cell id changed. Expect rat update from E to G
+    @Test
+    public void testRatRatchetWithCellChange() throws Exception {
+        CellIdentityGsm cellIdentity = new CellIdentityGsm(-1, -1, -1, -1, -1, -1);
+        NetworkRegistrationState dataResult = new NetworkRegistrationState(
+                0, 0, 1, 2, 0, false, null, cellIdentity, 1);
+        sst.mPollingContext[0] = 2;
+        // update data reg state to be in service
+        sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_GPRS,
+                new AsyncResult(sst.mPollingContext, dataResult, null)));
+        waitForMs(200);
+        assertEquals(ServiceState.STATE_IN_SERVICE, mSST.getCurrentDataConnectionState());
+
+        NetworkRegistrationState voiceResult = new NetworkRegistrationState(
+                0, 0, 1, 2, 0, false, null, cellIdentity, false, 0, 0, 0);
+        sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_REGISTRATION,
+                new AsyncResult(sst.mPollingContext, voiceResult, null)));
+        waitForMs(200);
+        assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_EDGE, sst.mSS.getRilVoiceRadioTechnology());
+
+        // RAT: EDGE -> GPRS cell ID: -1 -> 5
+        cellIdentity = new CellIdentityGsm(-1, -1, -1, 5, -1, -1);
+        voiceResult = new NetworkRegistrationState(
+                0, 0, 1, 1, 0, false, null, cellIdentity, false, 0, 0, 0);
+        sst.mPollingContext[0] = 2;
+        sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_GPRS,
+                new AsyncResult(sst.mPollingContext, dataResult, null)));
+        waitForMs(200);
+        assertEquals(ServiceState.STATE_IN_SERVICE, mSST.getCurrentDataConnectionState());
+
+        sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_REGISTRATION,
+                new AsyncResult(sst.mPollingContext, voiceResult, null)));
+        waitForMs(200);
+        assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_GPRS, sst.mSS.getRilVoiceRadioTechnology());
+    }
+
+    // Edge, GPRS and UMTS are grouped under the same family where Edge > GPRS > UMTS  .
+    // Expect no rat update from E to G immediately following cell id change.
+    // Expect ratratchet (from G to UMTS) for the following rat update within the cell location.
+    @Test
+    public void testRatRatchetWithCellChangeBeforeRatChange() throws Exception {
+        // cell ID update
+        CellIdentityGsm cellIdentity = new CellIdentityGsm(-1, -1, -1, 5, -1, -1);
+        NetworkRegistrationState dataResult = new NetworkRegistrationState(
+                0, 0, 1, 2, 0, false, null, cellIdentity, 1);
+        sst.mPollingContext[0] = 2;
+        // update data reg state to be in service
+        sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_GPRS,
+                new AsyncResult(sst.mPollingContext, dataResult, null)));
+        waitForMs(200);
+        assertEquals(ServiceState.STATE_IN_SERVICE, mSST.getCurrentDataConnectionState());
+
+        NetworkRegistrationState voiceResult = new NetworkRegistrationState(
+                0, 0, 1, 2, 0, false, null, cellIdentity, false, 0, 0, 0);
+        sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_REGISTRATION,
+                new AsyncResult(sst.mPollingContext, voiceResult, null)));
+        waitForMs(200);
+        assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_EDGE, sst.mSS.getRilVoiceRadioTechnology());
+
+        // RAT: EDGE -> GPRS, cell ID unchanged. Expect no rat ratchet following cell Id change.
+        voiceResult = new NetworkRegistrationState(
+                0, 0, 1, 1, 0, false, null, cellIdentity, false, 0, 0, 0);
+        sst.mPollingContext[0] = 2;
+        sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_GPRS,
+                new AsyncResult(sst.mPollingContext, dataResult, null)));
+        waitForMs(200);
+        assertEquals(ServiceState.STATE_IN_SERVICE, mSST.getCurrentDataConnectionState());
+
+        sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_REGISTRATION,
+                new AsyncResult(sst.mPollingContext, voiceResult, null)));
+        waitForMs(200);
+        assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_GPRS, sst.mSS.getRilVoiceRadioTechnology());
+
+        // RAT: GPRS -> UMTS
+        voiceResult = new NetworkRegistrationState(
+                0, 0, 1, 3, 0, false, null, cellIdentity, false, 0, 0, 0);
+        sst.mPollingContext[0] = 2;
+        sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_GPRS,
+                new AsyncResult(sst.mPollingContext, dataResult, null)));
+        waitForMs(200);
+        assertEquals(ServiceState.STATE_IN_SERVICE, mSST.getCurrentDataConnectionState());
+
+        sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_REGISTRATION,
+                new AsyncResult(sst.mPollingContext, voiceResult, null)));
+        waitForMs(200);
+        assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_GPRS, sst.mSS.getRilVoiceRadioTechnology());
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 0f75a94..782d489 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -64,7 +64,6 @@
 import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
 import com.android.internal.telephony.test.SimulatedCommands;
 import com.android.internal.telephony.test.SimulatedCommandsVerifier;
-import com.android.internal.telephony.uicc.IccCardProxy;
 import com.android.internal.telephony.uicc.IccCardStatus;
 import com.android.internal.telephony.uicc.IccRecords;
 import com.android.internal.telephony.uicc.IsimUiccRecords;
@@ -109,8 +108,6 @@
     @Mock
     protected UiccController mUiccController;
     @Mock
-    protected IccCardProxy mIccCardProxy;
-    @Mock
     protected UiccProfile mUiccProfile;
     @Mock
     protected CallManager mCallManager;
@@ -328,9 +325,6 @@
         doReturn(mSST).when(mTelephonyComponentFactory)
                 .makeServiceStateTracker(nullable(GsmCdmaPhone.class),
                         nullable(CommandsInterface.class));
-        doReturn(mIccCardProxy).when(mTelephonyComponentFactory)
-                .makeIccCardProxy(nullable(Context.class), nullable(CommandsInterface.class),
-                        anyInt());
         doReturn(mUiccProfile).when(mTelephonyComponentFactory)
                 .makeUiccProfile(nullable(Context.class), nullable(CommandsInterface.class),
                         nullable(IccCardStatus.class), anyInt(), nullable(UiccCard.class));
@@ -419,7 +413,7 @@
         doReturn(mRuimRecords).when(mUiccCardApplication3gpp2).getIccRecords();
         doReturn(mIsimUiccRecords).when(mUiccCardApplicationIms).getIccRecords();
 
-        //mIccCardProxy
+        //mUiccProfile
         doReturn(mSimRecords).when(mUiccProfile).getIccRecords();
         doAnswer(new Answer<IccRecords>() {
             public IccRecords answer(InvocationOnMock invocation) {
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 f13d2c2..0097ef6 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
@@ -35,6 +35,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
@@ -524,6 +525,36 @@
         assertEquals(SetupResult.SUCCESS, setLinkProperties(response, linkProperties));
     }
 
+    @Test
+    @SmallTest
+    public void testStartKeepaliveWLAN() throws Exception {
+        testConnectEvent();
+        waitForMs(200);
+
+        DataServiceManager mockDsm = mock(DataServiceManager.class);
+        doReturn(TransportType.WLAN).when(mockDsm).getTransportType();
+        replaceInstance(DataConnection.class, "mDataServiceManager", mDc, mockDsm);
+
+        final int sessionHandle = 0xF00;
+        final int slotId = 3;
+        final int interval = 10; // seconds
+        // Construct a new KeepalivePacketData request as we would receive from a Network Agent,
+        // and check that the packet is sent to the RIL.
+        KeepalivePacketData kd = KeepalivePacketData.nattKeepalivePacket(
+                NetworkUtils.numericToInetAddress("1.2.3.4"),
+                1234,
+                NetworkUtils.numericToInetAddress("8.8.8.8"),
+                4500);
+        mDc.obtainMessage(
+                DataConnection.EVENT_KEEPALIVE_START_REQUEST, slotId, interval, kd).sendToTarget();
+        waitForMs(100);
+        // testStartStopNattKeepalive() verifies that this request is passed with WWAN.
+        // Thus, even though we can't see the response in NetworkAgent, we can verify that the
+        // CommandsInterface never receives a request and infer that it was dropped due to WLAN.
+        verify(mSimulatedCommandsVerifier, times(0))
+                .startNattKeepalive(anyInt(), eq(kd), eq(interval * 1000), any(Message.class));
+    }
+
     public void checkStartStopNattKeepalive(boolean useCondensedFlow) throws Exception {
         testConnectEvent();
         waitForMs(200);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/IccCardProxyTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccCardProxyTest.java
deleted file mode 100644
index 479acb7..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/IccCardProxyTest.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.telephony.uicc;
-
-import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.doReturn;
-
-import android.os.HandlerThread;
-import android.support.test.filters.FlakyTest;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.IccCardConstants.State;
-import com.android.internal.telephony.TelephonyTest;
-import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
-import com.android.internal.telephony.uicc.IccCardStatus.CardState;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.mockito.Mock;
-
-public class IccCardProxyTest extends TelephonyTest {
-    private IccCardProxy mIccCardProxyUT;
-    // private UiccCard mUiccCard;
-    private IccCardProxyHandlerThread mIccCardProxyHandlerThread;
-    private static final int PHONE_ID = 0;
-    private static final int PHONE_COUNT = 1;
-
-    private static final int SCARY_SLEEP_MS = 200;
-    // Must match IccCardProxy.EVENT_ICC_CHANGED
-    private static final int EVENT_ICC_CHANGED = 3;
-
-    @Mock private IccCardStatus mIccCardStatus;
-    @Mock private UiccCard mUiccCard;
-    @Mock private UiccCardApplication mUiccCardApplication;
-
-    private class IccCardProxyHandlerThread extends HandlerThread {
-
-        private IccCardProxyHandlerThread(String name) {
-            super(name);
-        }
-
-        @Override
-        public void onLooperPrepared() {
-            /* create a new UICC Controller associated with the simulated Commands */
-            mIccCardProxyUT = new IccCardProxy(mContext, mSimulatedCommands, PHONE_ID);
-            setReady(true);
-        }
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp(this.getClass().getSimpleName());
-        doReturn(PHONE_COUNT).when(mTelephonyManager).getPhoneCount();
-        doReturn(PHONE_COUNT).when(mTelephonyManager).getSimCount();
-        mSimulatedCommands.setIccCardStatus(mIccCardStatus);
-        mIccCardProxyHandlerThread = new IccCardProxyHandlerThread(TAG);
-        mIccCardProxyHandlerThread.start();
-        waitUntilReady();
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        mIccCardProxyHandlerThread.quitSafely();
-        super.tearDown();
-    }
-
-    @Test
-    @SmallTest
-    public void testInitialCardState() {
-        assertEquals(mIccCardProxyUT.getState(), State.UNKNOWN);
-    }
-
-    @Test
-    @Ignore
-    @FlakyTest
-    @SmallTest
-    public void testPowerOn() {
-        mSimulatedCommands.setRadioPower(true, null);
-        mSimulatedCommands.notifyRadioOn();
-        doReturn(mUiccCard).when(mUiccController).getUiccCard(anyInt());
-        mIccCardProxyUT.sendMessage(mIccCardProxyUT.obtainMessage(EVENT_ICC_CHANGED));
-
-        waitForMs(SCARY_SLEEP_MS);
-        assertEquals(CommandsInterface.RadioState.RADIO_ON, mSimulatedCommands.getRadioState());
-        assertEquals(mIccCardProxyUT.getState(), State.NOT_READY);
-        logd("IccCardProxy state = " + mIccCardProxyUT.getState());
-    }
-
-    @Test
-    @Ignore
-    @FlakyTest
-    @SmallTest
-    public void testCardLoaded() {
-        testPowerOn();
-        doReturn(CardState.CARDSTATE_PRESENT).when(mUiccCard).getCardState();
-        mIccCardProxyUT.sendMessage(mIccCardProxyUT.obtainMessage(EVENT_ICC_CHANGED));
-
-        waitForMs(SCARY_SLEEP_MS);
-        assertEquals(mIccCardProxyUT.getState(), State.NOT_READY);
-    }
-
-    @Test
-    @Ignore
-    @FlakyTest
-    @SmallTest
-    public void testAppNotLoaded() {
-        testPowerOn();
-        doReturn(CardState.CARDSTATE_PRESENT).when(mUiccCard).getCardState();
-        mIccCardProxyUT.sendMessage(mIccCardProxyUT.obtainMessage(EVENT_ICC_CHANGED));
-        doReturn(AppState.APPSTATE_UNKNOWN).when(mUiccCardApplication).getState();
-        doReturn(mUiccCardApplication).when(mUiccCard).getApplication(anyInt());
-
-        waitForMs(SCARY_SLEEP_MS);
-        assertEquals(mIccCardProxyUT.getState(), State.NOT_READY);
-    }
-
-    @Test
-    @Ignore
-    @FlakyTest
-    @SmallTest
-    public void testAppReady() {
-        testPowerOn();
-        doReturn(CardState.CARDSTATE_PRESENT).when(mUiccCard).getCardState();
-        mIccCardProxyUT.sendMessage(mIccCardProxyUT.obtainMessage(EVENT_ICC_CHANGED));
-        doReturn(AppState.APPSTATE_READY).when(mUiccCardApplication).getState();
-        doReturn(mUiccCardApplication).when(mUiccCard).getApplication(anyInt());
-
-        waitForMs(SCARY_SLEEP_MS);
-        assertEquals(mIccCardProxyUT.getState(), State.READY);
-    }
-}