am 93fc415e: Merge "Update SubscriptionManager API as per API council." into lmp-mr1-dev automerge: 43bbf30 automerge: e76308c

* commit '93fc415e6219f59a5b1f2d6fd5e1647551a27742':
  Update SubscriptionManager API as per API council.
diff --git a/Android.mk b/Android.mk
index 11bcf45..1a6b8cc 100644
--- a/Android.mk
+++ b/Android.mk
@@ -378,6 +378,7 @@
 	telephony/java/com/android/internal/telephony/ITelephony.aidl \
 	telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
 	telephony/java/com/android/internal/telephony/ISms.aidl \
+	telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl \
 	telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
 	telephony/java/com/android/internal/telephony/ISub.aidl \
 	telephony/java/com/android/internal/telephony/IMms.aidl \
diff --git a/api/current.txt b/api/current.txt
index 63be781..8dd1323 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28664,6 +28664,7 @@
     method public void downloadMultimediaMessage(android.content.Context, java.lang.String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
     method public android.os.Bundle getCarrierConfigValues();
     method public static android.telephony.SmsManager getDefault();
+    method public static int getDefaultSmsSubscriptionId();
     method public static android.telephony.SmsManager getSmsManagerForSubscriber(int);
     method public int getSubId();
     method public void injectSmsPdu(byte[], java.lang.String, android.app.PendingIntent);
@@ -28782,7 +28783,7 @@
     field public byte[] encodedScAddress;
   }
 
-  public class SubInfoRecord implements android.os.Parcelable {
+  public class SubscriptionInfo implements android.os.Parcelable {
     method public android.graphics.Bitmap createIconBitmap(android.content.Context);
     method public int describeContents();
     method public int getDataRoaming();
@@ -28796,25 +28797,23 @@
     method public int getSimSlotIndex();
     method public int getSubscriptionId();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.telephony.SubInfoRecord> CREATOR;
+    field public static final android.os.Parcelable.Creator<android.telephony.SubscriptionInfo> CREATOR;
+  }
+
+  public class SubscriptionListener {
+    ctor public SubscriptionListener();
+    ctor public SubscriptionListener(android.os.Looper);
+    method public void onSubscriptionInfoChanged();
+    field public static final int LISTEN_SUBSCRIPTION_INFO_LIST_CHANGED = 1; // 0x1
   }
 
   public class SubscriptionManager implements android.provider.BaseColumns {
-    method public static java.util.List<android.telephony.SubInfoRecord> getActiveSubInfoList();
-    method public static int getDefaultSmsSubId();
-    method public static int getSlotId(int);
-    method public static android.telephony.SubInfoRecord getSubInfoForSubscriber(int);
-    method public static java.util.List<android.telephony.SubInfoRecord> getSubInfoUsingSlotId(int);
-    method public static boolean isValidSubId(int);
-    field public static final int ASK_USER_SUB_ID = -1001; // 0xfffffc17
-    field public static final int DEFAULT_PHONE_ID = 2147483647; // 0x7fffffff
-    field public static final int DEFAULT_SUB_ID = 2147483647; // 0x7fffffff
-    field public static final int INVALID_PHONE_ID = -1000; // 0xfffffc18
-    field public static final int INVALID_SLOT_ID = -1000; // 0xfffffc18
+    method public static java.util.List<android.telephony.SubscriptionInfo> getActiveSubscriptionInfoList();
+    method public static android.telephony.SubscriptionInfo getSubscriptionInfoForSubscriber(int);
+    method public static java.util.List<android.telephony.SubscriptionInfo> getSubscriptionInfoUsingSlotId(int);
+    method public static void register(android.content.Context, android.telephony.SubscriptionListener, int);
+    method public static void unregister(android.content.Context, android.telephony.SubscriptionListener);
     field public static final int INVALID_SUB_ID = -1000; // 0xfffffc18
-    field public static final java.lang.String MCC = "mcc";
-    field public static final java.lang.String MNC = "mnc";
-    field public static final int SIM_NOT_INSERTED = -1; // 0xffffffff
   }
 
   public class TelephonyManager {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index ba93213..2ed021a 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -34,6 +34,8 @@
 import android.telephony.CellLocation;
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.Rlog;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionListener;
 import android.telephony.TelephonyManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.PhoneStateListener;
@@ -56,6 +58,7 @@
 import java.io.PrintWriter;
 
 import com.android.internal.app.IBatteryStats;
+import com.android.internal.telephony.ISubscriptionListener;
 import com.android.internal.telephony.ITelephonyRegistry;
 import com.android.internal.telephony.IPhoneStateListener;
 import com.android.internal.telephony.DefaultPhoneNotifier;
@@ -90,19 +93,30 @@
         IBinder binder;
 
         IPhoneStateListener callback;
+        ISubscriptionListener subscriptionListenerCallback;
 
         int callerUid;
 
         int events;
 
-        int subId;
+        int subId = SubscriptionManager.INVALID_SUB_ID;
 
-        int phoneId;
+        int phoneId = SubscriptionManager.INVALID_PHONE_ID;
+
+        boolean matchPhoneStateListenerEvent(int events) {
+            return (callback != null) && ((events & this.events) != 0);
+        }
+
+        boolean matchSubscriptionListenerEvent(int events) {
+            return (subscriptionListenerCallback != null) && ((events & this.events) != 0);
+        }
 
         @Override
         public String toString() {
-            return "{pkgForDebug=" + pkgForDebug + " callerUid=" + callerUid + " subId=" + subId +
-                    " phoneId=" + phoneId + " events=" + Integer.toHexString(events) + "}";
+            return "{pkgForDebug=" + pkgForDebug + " binder=" + binder + " callback=" + callback
+                    + " subscriptionListenererCallback=" + subscriptionListenerCallback
+                    + " callerUid=" + callerUid + " subId=" + subId + " phoneId=" + phoneId
+                    + " events=" + Integer.toHexString(events) + "}";
         }
     }
 
@@ -325,6 +339,101 @@
     }
 
     @Override
+    public void registerSubscriptionListener(String pkgForDebug, ISubscriptionListener callback,
+            int events) {
+        int callerUid = UserHandle.getCallingUserId();
+        int myUid = UserHandle.myUserId();
+        if (VDBG) {
+            log("listen sl: E pkg=" + pkgForDebug + " events=0x" + Integer.toHexString(events)
+                + " myUid=" + myUid + " callerUid=" + callerUid + " callback=" + callback
+                + " callback.asBinder=" + callback.asBinder());
+        }
+
+        if (events != 0) {
+            /* Checks permission and throws Security exception */
+            checkSubscriptionListenerPermission(events);
+            Record r = null;
+
+            synchronized (mRecords) {
+                // register
+                find_and_add: {
+                    IBinder b = callback.asBinder();
+                    final int N = mRecords.size();
+                    for (int i = 0; i < N; i++) {
+                        r = mRecords.get(i);
+                        if (b == r.binder) {
+                            break find_and_add;
+                        }
+                    }
+                    r = new Record();
+                    r.binder = b;
+                    mRecords.add(r);
+                    if (DBG) log("listen sl: add new record");
+                }
+
+                r.subscriptionListenerCallback = callback;
+                r.pkgForDebug = pkgForDebug;
+                r.callerUid = callerUid;
+                r.events = events;
+                if (DBG) {
+                    log("listen sl:  Register r=" + r);
+                }
+            }
+
+            // Always notify when a listen is established.
+            if (r.matchSubscriptionListenerEvent(
+                    SubscriptionListener.LISTEN_SUBSCRIPTION_INFO_LIST_CHANGED)) {
+                try {
+                    if (VDBG) log("listen sl: send to r=" + r);
+                    r.subscriptionListenerCallback.onSubscriptionInfoChanged();
+                    if (VDBG) log("listen sl: sent to r=" + r);
+                } catch (RemoteException e) {
+                    if (VDBG) log("listen sl: remote exception sending to r=" + r + " e=" + e);
+                    remove(r.binder);
+                }
+            }
+        } else {
+            if (DBG) log("listen sl: Unregister as event is LISTEN_NONE");
+            unregisterSubscriptionListener(pkgForDebug, callback);
+        }
+    }
+
+    @Override
+    public void unregisterSubscriptionListener(String pkgForDebug, ISubscriptionListener callback) {
+        if (DBG) log("listen sl: Unregister as event is LISTEN_NONE");
+        remove(callback.asBinder());
+    }
+
+    private void checkSubscriptionListenerPermission(int events) {
+        if ((events & SubscriptionListener.LISTEN_SUBSCRIPTION_INFO_LIST_CHANGED) != 0) {
+            mContext.enforceCallingOrSelfPermission(
+                    SubscriptionListener.PERMISSION_LISTEN_SUBSCRIPTION_INFO_LIST_CHANGED, null);
+        }
+    }
+
+    @Override
+    public void notifySubscriptionInfoChanged() {
+        if (VDBG) log("notifySubscriptionInfoChanged:");
+        synchronized (mRecords) {
+            mRemoveList.clear();
+            for (Record r : mRecords) {
+                if (r.matchSubscriptionListenerEvent(
+                        SubscriptionListener.LISTEN_SUBSCRIPTION_INFO_LIST_CHANGED)) {
+                    try {
+                        if (VDBG) log("notifySubscriptionInfoChanged: send to r=" + r);
+                        r.subscriptionListenerCallback.onSubscriptionInfoChanged();
+                        if (VDBG) log("notifySubscriptionInfoChanged: sent to r=" + r);
+                    } catch (RemoteException ex) {
+                        if (VDBG) log("notifySubscriptionInfoChanged: RemoteException r=" + r);
+                        mRemoveList.add(r.binder);
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+    }
+
+    @Override
     public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
             boolean notifyNow) {
         listenForSubscriber(SubscriptionManager.DEFAULT_SUB_ID, pkgForDebug, callback, events,
@@ -513,6 +622,7 @@
             final int recordCount = mRecords.size();
             for (int i = 0; i < recordCount; i++) {
                 if (mRecords.get(i).binder == binder) {
+                    if (VDBG) log("remove: binder=" + binder);
                     mRecords.remove(i);
                     return;
                 }
@@ -531,7 +641,7 @@
 
         synchronized (mRecords) {
             for (Record r : mRecords) {
-                if (((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) &&
+                if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_CALL_STATE) &&
                         (r.subId == SubscriptionManager.DEFAULT_SUB_ID)) {
                     try {
                         r.callback.onCallStateChanged(state, incomingNumber);
@@ -559,7 +669,7 @@
                 mCallState[phoneId] = state;
                 mCallIncomingNumber[phoneId] = incomingNumber;
                 for (Record r : mRecords) {
-                    if (((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) &&
+                    if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_CALL_STATE) &&
                             (r.subId == subId) &&
                             (r.subId != SubscriptionManager.DEFAULT_SUB_ID)) {
                         try {
@@ -595,7 +705,7 @@
                         log("notifyServiceStateForSubscriber: r=" + r + " subId=" + subId
                                 + " phoneId=" + phoneId + " state=" + state);
                     }
-                    if (((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) &&
+                    if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SERVICE_STATE) &&
                             idMatch(r.subId, subId, phoneId)) {
                         try {
                             if (DBG) {
@@ -640,7 +750,8 @@
                         log("notifySignalStrengthForSubscriber: r=" + r + " subId=" + subId
                                 + " phoneId=" + phoneId + " ss=" + signalStrength);
                     }
-                    if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) &&
+                    if (r.matchPhoneStateListenerEvent(
+                                PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) &&
                             idMatch(r.subId, subId, phoneId)) {
                         try {
                             if (DBG) {
@@ -653,7 +764,7 @@
                             mRemoveList.add(r.binder);
                         }
                     }
-                    if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) &&
+                    if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SIGNAL_STRENGTH) &&
                             idMatch(r.subId, subId, phoneId)){
                         try {
                             int gsmSignalStrength = signalStrength.getGsmSignalStrength();
@@ -750,7 +861,8 @@
             if (validatePhoneId(phoneId)) {
                 mMessageWaiting[phoneId] = mwi;
                 for (Record r : mRecords) {
-                    if (((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) &&
+                    if (r.matchPhoneStateListenerEvent(
+                            PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) &&
                             idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onMessageWaitingIndicatorChanged(mwi);
@@ -781,7 +893,8 @@
             if (validatePhoneId(phoneId)) {
                 mCallForwarding[phoneId] = cfi;
                 for (Record r : mRecords) {
-                    if (((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) &&
+                    if (r.matchPhoneStateListenerEvent(
+                            PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) &&
                             idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onCallForwardingIndicatorChanged(cfi);
@@ -807,7 +920,7 @@
             int phoneId = SubscriptionManager.getPhoneId(subId);
             mDataActivity[phoneId] = state;
             for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
+                if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_DATA_ACTIVITY)) {
                     try {
                         r.callback.onDataActivity(state);
                     } catch (RemoteException ex) {
@@ -878,7 +991,8 @@
                         + ", " + mDataConnectionNetworkType[phoneId] + ")");
                 }
                 for (Record r : mRecords) {
-                    if (((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) &&
+                    if (r.matchPhoneStateListenerEvent(
+                            PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) &&
                             idMatch(r.subId, subId, phoneId)) {
                         try {
                             log("Notify data connection state changed on sub: " +
@@ -895,7 +1009,8 @@
             mPreciseDataConnectionState = new PreciseDataConnectionState(state, networkType,
                     apnType, apn, reason, linkProperties, "");
             for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
+                if (r.matchPhoneStateListenerEvent(
+                        PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)) {
                     try {
                         r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
                     } catch (RemoteException ex) {
@@ -930,7 +1045,8 @@
                     TelephonyManager.DATA_UNKNOWN,TelephonyManager.NETWORK_TYPE_UNKNOWN,
                     apnType, "", reason, null, "");
             for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
+                if (r.matchPhoneStateListenerEvent(
+                        PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)) {
                     try {
                         r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
                     } catch (RemoteException ex) {
@@ -989,7 +1105,7 @@
         synchronized (mRecords) {
             mOtaspMode = otaspMode;
             for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
+                if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_OTASP_CHANGED)) {
                     try {
                         r.callback.onOtaspChanged(otaspMode);
                     } catch (RemoteException ex) {
@@ -1015,7 +1131,7 @@
                     DisconnectCause.NOT_VALID,
                     PreciseDisconnectCause.NOT_VALID);
             for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
+                if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_PRECISE_CALL_STATE)) {
                     try {
                         r.callback.onPreciseCallStateChanged(mPreciseCallState);
                     } catch (RemoteException ex) {
@@ -1038,7 +1154,7 @@
             mPreciseCallState = new PreciseCallState(mRingingCallState, mForegroundCallState,
                     mBackgroundCallState, disconnectCause, preciseDisconnectCause);
             for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
+                if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_PRECISE_CALL_STATE)) {
                     try {
                         r.callback.onPreciseCallStateChanged(mPreciseCallState);
                     } catch (RemoteException ex) {
@@ -1062,7 +1178,8 @@
                     TelephonyManager.DATA_UNKNOWN, TelephonyManager.NETWORK_TYPE_UNKNOWN,
                     apnType, apn, reason, null, failCause);
             for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
+                if (r.matchPhoneStateListenerEvent(
+                        PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)) {
                     try {
                         r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
                     } catch (RemoteException ex) {
@@ -1083,7 +1200,7 @@
         synchronized (mRecords) {
             mVoLteServiceState = lteState;
             for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_VOLTE_STATE) != 0) {
+                if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_VOLTE_STATE)) {
                     try {
                         r.callback.onVoLteServiceStateChanged(
                                 new VoLteServiceState(mVoLteServiceState));
@@ -1106,7 +1223,8 @@
                 if (VDBG) {
                     log("notifyOemHookRawEventForSubscriber:  r=" + r + " subId=" + subId);
                 }
-                if (((r.events & PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT) != 0) &&
+                if ((r.matchPhoneStateListenerEvent(
+                        PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT)) &&
                         ((r.subId == subId) ||
                         (r.subId == SubscriptionManager.DEFAULT_SUB_ID))) {
                     try {
@@ -1337,7 +1455,9 @@
     }
 
     private void handleRemoveListLocked() {
-        if (mRemoveList.size() > 0) {
+        int size = mRemoveList.size();
+        if (VDBG) log("handleRemoveListLocked: mRemoveList.size()=" + size);
+        if (size > 0) {
             for (IBinder b: mRemoveList) {
                 remove(b);
             }
@@ -1351,7 +1471,7 @@
         boolean valid = false;
         try {
             foregroundUser = ActivityManager.getCurrentUser();
-            valid = r.callerUid ==  foregroundUser && (r.events & events) != 0;
+            valid = r.callerUid ==  foregroundUser && r.matchPhoneStateListenerEvent(events);
             if (DBG | DBG_LOC) {
                 log("validateEventsAndUserLocked: valid=" + valid
                         + " r.callerUid=" + r.callerUid + " foregroundUser=" + foregroundUser
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index 7354137..2c9a468 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -72,6 +72,9 @@
 import android.provider.Telephony.Carriers;
 import android.provider.Telephony.Sms.Intents;
 import android.telephony.SmsMessage;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionListener;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.gsm.GsmCellLocation;
 import android.text.TextUtils;
@@ -88,6 +91,7 @@
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.Date;
+import java.util.List;
 import java.util.Map.Entry;
 import java.util.Properties;
 
@@ -452,26 +456,35 @@
                     || Intent.ACTION_SCREEN_OFF.equals(action)
                     || Intent.ACTION_SCREEN_ON.equals(action)) {
                 updateLowPowerMode();
-            } else if (action.equals(SIM_STATE_CHANGED)
-                    || action.equals(TelephonyIntents.ACTION_SUBINFO_CONTENT_CHANGE)
-                    || action.equals(TelephonyIntents.ACTION_SUBINFO_RECORD_UPDATED)) {
-                Log.d(TAG, "received SIM realted action: " + action);
-                TelephonyManager phone = (TelephonyManager)
-                        mContext.getSystemService(Context.TELEPHONY_SERVICE);
-                String mccMnc = phone.getSimOperator();
-                if (!TextUtils.isEmpty(mccMnc)) {
-                    Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
-                    synchronized (mLock) {
-                        reloadGpsProperties(context, mProperties);
-                        mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
-                    }
-                } else {
-                    Log.d(TAG, "SIM MCC/MNC is still not available");
-                }
+            } else if (action.equals(SIM_STATE_CHANGED)) {
+                subscriptionOrSimChanged(context);
             }
         }
     };
 
+    private final SubscriptionListener mSubscriptionListener = new SubscriptionListener() {
+        @Override
+        public void onSubscriptionInfoChanged() {
+            subscriptionOrSimChanged(mContext);
+        }
+    };
+
+    private void subscriptionOrSimChanged(Context context) {
+        Log.d(TAG, "received SIM realted action: ");
+        TelephonyManager phone = (TelephonyManager)
+                mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        String mccMnc = phone.getSimOperator();
+        if (!TextUtils.isEmpty(mccMnc)) {
+            Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
+            synchronized (mLock) {
+                reloadGpsProperties(context, mProperties);
+                mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
+            }
+        } else {
+            Log.d(TAG, "SIM MCC/MNC is still not available");
+        }
+    }
+
     private void checkSmsSuplInit(Intent intent) {
         SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
         for (int i=0; i <messages.length; i++) {
@@ -626,6 +639,16 @@
                                                 mNetInitiatedListener,
                                                 mSuplEsEnabled);
 
+        // TODO: When this object "finishes" we should unregister by invoking
+        // SubscriptionManager.unregister(mContext, mSubscriptionListener);
+        // This is not strictly necessary because it will be unregistered if the
+        // notification fails but it is good form.
+
+        // Register for SubscriptionInfo list changes which is guaranteed
+        // to invoke onSubscriptionInfoChanged the first time.
+        SubscriptionManager.register(mContext, mSubscriptionListener,
+                SubscriptionListener.LISTEN_SUBSCRIPTION_INFO_LIST_CHANGED);
+
         // construct handler, listen for events
         mHandler = new ProviderHandler(looper);
         listenForBroadcasts();
@@ -735,10 +758,6 @@
         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
         intentFilter.addAction(Intent.ACTION_SCREEN_ON);
         intentFilter.addAction(SIM_STATE_CHANGED);
-        // TODO: remove the use TelephonyIntents. We are using it because SIM_STATE_CHANGED
-        // is not reliable at the moment.
-        intentFilter.addAction(TelephonyIntents.ACTION_SUBINFO_CONTENT_CHANGE);
-        intentFilter.addAction(TelephonyIntents.ACTION_SUBINFO_RECORD_UPDATED);
         mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, mHandler);
     }
 
diff --git a/telephony/java/android/telephony/SubInfoRecord.aidl b/telephony/java/android/telephony/SubscriptionInfo.aidl
similarity index 95%
rename from telephony/java/android/telephony/SubInfoRecord.aidl
rename to telephony/java/android/telephony/SubscriptionInfo.aidl
index a2de676..1e13732 100755
--- a/telephony/java/android/telephony/SubInfoRecord.aidl
+++ b/telephony/java/android/telephony/SubscriptionInfo.aidl
@@ -16,4 +16,4 @@
 
 package android.telephony;
 
-parcelable SubInfoRecord;
+parcelable SubscriptionInfo;
diff --git a/telephony/java/android/telephony/SubInfoRecord.java b/telephony/java/android/telephony/SubscriptionInfo.java
similarity index 92%
rename from telephony/java/android/telephony/SubInfoRecord.java
rename to telephony/java/android/telephony/SubscriptionInfo.java
index 89a6bd4..26f17c8 100644
--- a/telephony/java/android/telephony/SubInfoRecord.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -31,7 +31,7 @@
 /**
  * A Parcelable class for Subscription Information.
  */
-public class SubInfoRecord implements Parcelable {
+public class SubscriptionInfo implements Parcelable {
 
     /**
      * Subscription Identifier, this is a device unique number
@@ -99,7 +99,7 @@
     /**
      * @hide
      */
-    public SubInfoRecord(int id, String iccId, int simSlotIndex, CharSequence displayName,
+    public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
             CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
             Bitmap icon, int mcc, int mnc) {
         this.mId = id;
@@ -177,12 +177,12 @@
     }
 
     /**
-     * Creates and returns an icon {@code Bitmap} to represent this {@code SubInfoRecord} in a user
+     * Creates and returns an icon {@code Bitmap} to represent this {@code SubscriptionInfo} in a user
      * interface.
      *
      * @param context A {@code Context} to get the {@code DisplayMetrics}s from.
      *
-     * @return A bitmap icon for this {@code SubInfoRecord}.
+     * @return A bitmap icon for this {@code SubscriptionInfo}.
      */
     public Bitmap createIconBitmap(Context context) {
         int width = mIconBitmap.getWidth();
@@ -259,9 +259,9 @@
         return this.mMnc;
     }
 
-    public static final Parcelable.Creator<SubInfoRecord> CREATOR = new Parcelable.Creator<SubInfoRecord>() {
+    public static final Parcelable.Creator<SubscriptionInfo> CREATOR = new Parcelable.Creator<SubscriptionInfo>() {
         @Override
-        public SubInfoRecord createFromParcel(Parcel source) {
+        public SubscriptionInfo createFromParcel(Parcel source) {
             int id = source.readInt();
             String iccId = source.readString();
             int simSlotIndex = source.readInt();
@@ -275,13 +275,13 @@
             int mnc = source.readInt();
             Bitmap iconBitmap = Bitmap.CREATOR.createFromParcel(source);
 
-            return new SubInfoRecord(id, iccId, simSlotIndex, displayName, carrierName, nameSource,
+            return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName, nameSource,
                     iconTint, number, dataRoaming, iconBitmap, mcc, mnc);
         }
 
         @Override
-        public SubInfoRecord[] newArray(int size) {
-            return new SubInfoRecord[size];
+        public SubscriptionInfo[] newArray(int size) {
+            return new SubscriptionInfo[size];
         }
     };
 
diff --git a/telephony/java/android/telephony/SubscriptionListener.java b/telephony/java/android/telephony/SubscriptionListener.java
new file mode 100644
index 0000000..5c65333
--- /dev/null
+++ b/telephony/java/android/telephony/SubscriptionListener.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2014 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 android.telephony;
+
+import com.android.internal.telephony.ISub;
+import com.android.internal.telephony.ISubscriptionListener;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.telephony.Rlog;
+
+import java.util.List;
+
+/**
+ * A listener class for monitoring changes to Subscription state
+ * changes on the device.
+ * <p>
+ * Override the onXxxx methods in this class and passing to the listen method
+ * bitwise-or of the corresponding LISTEN_Xxxx bit flags below.
+ * <p>
+ * Note that access to some of the information is permission-protected. Your
+ * application won't receive updates for protected information unless it has
+ * the appropriate permissions declared in its manifest file. Where permissions
+ * apply, they are noted in the appropriate LISTEN_ flags.
+ */
+public class SubscriptionListener {
+    private static final String LOG_TAG = "SubscriptionListener";
+    private static final boolean DBG = false; // STOPSHIP if true
+
+    /**
+     * Permission for LISTEN_SUBSCRIPTION_INFO_LIST_CHANGED
+     *
+     * @hide
+     */
+    public static final String PERMISSION_LISTEN_SUBSCRIPTION_INFO_LIST_CHANGED =
+            android.Manifest.permission.READ_PHONE_STATE;
+
+    /**
+     *  Listen for changes to the SubscriptionInoList when listening for this event
+     *  it is guaranteed that on #onSubscriptionInfoChanged will be invoked. This initial
+     *  invocation should be used to call SubscriptionManager.getActiveSubscriptionInfoList()
+     *  to get the initial list.
+     *
+     *  Permissions: android.Manifest.permission.READ_PHONE_STATE
+     *  @see #onSubscriptionInfoChanged
+     */
+    public static final int LISTEN_SUBSCRIPTION_INFO_LIST_CHANGED = 0x00000001;
+
+    private final Handler mHandler;
+
+    /**
+     * Create a SubscriptionLitener for the device.
+     *
+     * This class requires Looper.myLooper() not return null. To supply your
+     * own non-null looper use PhoneStateListener(Looper looper) below.
+     */
+    public SubscriptionListener() {
+        this(Looper.myLooper());
+    }
+
+    /**
+     * Create a PhoneStateListener for the Phone using the specified subscription
+     * and non-null Looper.
+     */
+    public SubscriptionListener(Looper looper) {
+        if (DBG) log("ctor:  looper=" + looper);
+
+        ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+        mHandler = new Handler(looper) {
+            @Override
+            public void handleMessage(Message msg) {
+                if (DBG) {
+                    log("what=0x" + Integer.toHexString(msg.what) + " msg=" + msg);
+                }
+                switch (msg.what) {
+                    case LISTEN_SUBSCRIPTION_INFO_LIST_CHANGED:
+                        SubscriptionListener.this.onSubscriptionInfoChanged();
+                        break;
+                }
+            }
+        };
+    }
+
+    /**
+     * Callback invoked when there is any change to any SubscriptionInfo.
+     */
+    public void onSubscriptionInfoChanged() {
+        // default implementation empty
+    }
+
+    /**
+     * The callback methods need to be called on the handler thread where
+     * this object was created.  If the binder did that for us it'd be nice.
+     */
+    ISubscriptionListener callback = new ISubscriptionListener.Stub() {
+        @Override
+        public void onSubscriptionInfoChanged() {
+            Message msg = Message.obtain(mHandler, LISTEN_SUBSCRIPTION_INFO_LIST_CHANGED);
+            msg.sendToTarget();
+        }
+    };
+
+    private void log(String s) {
+        Rlog.d(LOG_TAG, s);
+    }
+}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 21d225d..78ab6870 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
 import android.provider.BaseColumns;
@@ -26,6 +27,7 @@
 import android.os.RemoteException;
 
 import com.android.internal.telephony.ISub;
+import com.android.internal.telephony.ITelephonyRegistry;
 import com.android.internal.telephony.PhoneConstants;
 
 import java.util.ArrayList;
@@ -43,28 +45,29 @@
     private static final boolean DBG = true;
     private static final boolean VDBG = false;
 
-    /** An invalid phone identifier */
-    public static final int INVALID_PHONE_ID = -1000;
+    /** An invalid subscription identifier */
+    public static final int INVALID_SUB_ID = -1000;
 
-    /** Indicates the caller wants the default phone id. */
-    public static final int DEFAULT_PHONE_ID = Integer.MAX_VALUE;
+    /** An invalid phone identifier */
+    /** @hide */
+    public static final int INVALID_PHONE_ID = -1;
 
     /** An invalid slot identifier */
-    public static final int INVALID_SLOT_ID = -1000;
+    /** @hide */
+    public static final int INVALID_SLOT_ID = -1;
+
+    /** Indicates the caller wants the default sub id. */
+    /** @hide */
+    public static final int DEFAULT_SUB_ID = Integer.MAX_VALUE;
+
+    /** Indicates the caller wants the default phone id. */
+    /** @hide */
+    public static final int DEFAULT_PHONE_ID = Integer.MAX_VALUE;
 
     /** Indicates the caller wants the default slot id. */
     /** @hide */
     public static final int DEFAULT_SLOT_ID = Integer.MAX_VALUE;
 
-    /** Indicates the user should be asked which subscription to use. */
-    public static final int ASK_USER_SUB_ID = -1001;
-
-    /** An invalid subscription identifier */
-    public static final int INVALID_SUB_ID = -1000;
-
-    /** Indicates the caller wants the default sub id. */
-    public static final int DEFAULT_SUB_ID = Integer.MAX_VALUE;
-
     /** Minimum possible subid that represents a subscription */
     /** @hide */
     public static final int MIN_SUB_ID_VALUE = 0;
@@ -77,31 +80,6 @@
     /** @hide */
     public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
 
-    /** @hide */
-    public static final int DEFAULT_INT_VALUE = -100;
-
-    /** @hide */
-    public static final String DEFAULT_STRING_VALUE = "N/A";
-
-    /** @hide */
-    public static final int EXTRA_VALUE_NEW_SIM = 1;
-
-    /** @hide */
-    public static final int EXTRA_VALUE_REMOVE_SIM = 2;
-    /** @hide */
-    public static final int EXTRA_VALUE_REPOSITION_SIM = 3;
-    /** @hide */
-    public static final int EXTRA_VALUE_NOCHANGE = 4;
-
-    /** @hide */
-    public static final String INTENT_KEY_DETECT_STATUS = "simDetectStatus";
-    /** @hide */
-    public static final String INTENT_KEY_SIM_COUNT = "simCount";
-    /** @hide */
-    public static final String INTENT_KEY_NEW_SIM_SLOT = "newSIMSlot";
-    /** @hide */
-    public static final String INTENT_KEY_NEW_SIM_STATUS = "newSIMStatus";
-
     /**
      * The ICC ID of a SIM.
      * <P>Type: TEXT (String)</P>
@@ -116,6 +94,7 @@
     public static final String SIM_ID = "sim_id";
 
     /** SIM is not inserted */
+    /** @hide */
     public static final int SIM_NOT_INSERTED = -1;
 
     /**
@@ -237,12 +216,14 @@
     /**
      * TelephonyProvider column name for the MCC associated with a SIM.
      * <P>Type: INTEGER (int)</P>
+     * @hide
      */
     public static final String MCC = "mcc";
 
     /**
      * TelephonyProvider column name for the MNC associated with a SIM.
      * <P>Type: INTEGER (int)</P>
+     * @hide
      */
     public static final String MNC = "mnc";
 
@@ -261,17 +242,70 @@
     }
 
     /**
-     * Get the SubInfoRecord associated with the subId
-     * @param subId The unique SubInfoRecord index in database
-     * @return SubInfoRecord, maybe null
+     * Register for changes to events defined by SubscriptionListener.LISTEN_Xxx. Some of
+     * the events will fire as registration completes, this could be before or after
+     * this method returns.
+     *
+     * @param listener an instance of SubscriptionListner with overridden methods the
+     *                 overridden method should match the bits defined in events.
+     * @param events is one or more of the SubscriptionListener.LISTEN_Xxx bits
      */
-    public static SubInfoRecord getSubInfoForSubscriber(int subId) {
+    public static void register(Context context, SubscriptionListener listener, int events) {
+        String pkgForDebug = context != null ? context.getPackageName() : "<unknown>";
+        if (DBG) {
+            logd("SubscriptionManager listen pkgForDebug=" + pkgForDebug
+                    + " events=0x" + Integer.toHexString(events) + " listener=" + listener);
+        }
+        try {
+            // We use the TelephonyRegistry as its runs in the system and thus is always
+            // available where as SubscriptionController could crash and not be available
+            ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
+                    "telephony.registry"));
+            if (tr != null) {
+                tr.registerSubscriptionListener(pkgForDebug, listener.callback, events);
+            }
+        } catch (RemoteException ex) {
+            // Should not happen
+        }
+    }
+
+    /**
+     * Unregister the listener.
+     *
+     * @param context
+     * @param listener
+     */
+    public static void unregister(Context context, SubscriptionListener listener) {
+        String pkgForDebug = context != null ? context.getPackageName() : "<unknown>";
+        if (DBG) {
+            logd("SubscriptionManager unregister pkgForDebug=" + pkgForDebug
+                    + " listener=" + listener);
+        }
+        try {
+            // We use the TelephonyRegistry as its runs in the system and thus is always
+            // available where as SubscriptionController could crash and not be available
+            ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
+                    "telephony.registry"));
+            if (tr != null) {
+                tr.unregisterSubscriptionListener(pkgForDebug, listener.callback);
+            }
+        } catch (RemoteException ex) {
+            // Should not happen
+        }
+    }
+
+    /**
+     * Get the SubscriptionInfo associated with the subId
+     * @param subId The unique SubscriptionInfo index in database
+     * @return SubscriptionInfo, maybe null
+     */
+    public static SubscriptionInfo getSubscriptionInfoForSubscriber(int subId) {
         if (!isValidSubId(subId)) {
-            logd("[getSubInfoForSubscriberx]- invalid subId");
+            logd("[getSubscriptionInfoForSubscriber]- invalid subId");
             return null;
         }
 
-        SubInfoRecord subInfo = null;
+        SubscriptionInfo subInfo = null;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -287,19 +321,19 @@
     }
 
     /**
-     * Get the SubInfoRecord according to an IccId
+     * Get the SubscriptionInfo according to an IccId
      * @param iccId the IccId of SIM card
-     * @return SubInfoRecord List, maybe empty but not null
+     * @return SubscriptionInfo List, maybe empty but not null
      * @hide
      */
-    public static List<SubInfoRecord> getSubInfoUsingIccId(String iccId) {
-        if (VDBG) logd("[getSubInfoUsingIccId]+ iccId=" + iccId);
+    public static List<SubscriptionInfo> getSubscriptionInfoUsingIccId(String iccId) {
+        if (VDBG) logd("[getSubscriptionInfoUsingIccId]+ iccId=" + iccId);
         if (iccId == null) {
-            logd("[getSubInfoUsingIccId]- null iccid");
+            logd("[getSubscriptionInfoUsingIccId]- null iccid");
             return null;
         }
 
-        List<SubInfoRecord> result = null;
+        List<SubscriptionInfo> result = null;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -312,24 +346,24 @@
 
 
         if (result == null) {
-            result = new ArrayList<SubInfoRecord>();
+            result = new ArrayList<SubscriptionInfo>();
         }
         return result;
     }
 
     /**
-     * Get the SubInfoRecord according to slotId
+     * Get the SubscriptionInfo according to slotId
      * @param slotId the slot which the SIM is inserted
-     * @return SubInfoRecord list, maybe empty but not null
+     * @return SubscriptionInfo list, maybe empty but not null
      */
-    public static List<SubInfoRecord> getSubInfoUsingSlotId(int slotId) {
+    public static List<SubscriptionInfo> getSubscriptionInfoUsingSlotId(int slotId) {
         // FIXME: Consider never returning null
         if (!isValidSlotId(slotId)) {
-            logd("[getSubInfoUsingSlotId]- invalid slotId");
+            logd("[getSubscriptionInfoUsingSlotId]- invalid slotId");
             return null;
         }
 
-        List<SubInfoRecord> result = null;
+        List<SubscriptionInfo> result = null;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -342,21 +376,21 @@
 
 
         if (result == null) {
-            result = new ArrayList<SubInfoRecord>();
+            result = new ArrayList<SubscriptionInfo>();
         }
         return result;
     }
 
     /**
-     * Get all the SubInfoRecord(s) in subInfo database
-     * @return List of all SubInfoRecords in database, include those that were inserted before
+     * Get all the SubscriptionInfo(s) in subInfo database
+     * @return List of all SubscriptionInfos in database, include those that were inserted before
      * maybe empty but not null.
      * @hide
      */
-    public static List<SubInfoRecord> getAllSubInfoList() {
-        if (VDBG) logd("[getAllSubInfoList]+");
+    public static List<SubscriptionInfo> getAllSubscriptionInfoList() {
+        if (VDBG) logd("[getAllSubscriptionInfoList]+");
 
-        List<SubInfoRecord> result = null;
+        List<SubscriptionInfo> result = null;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -368,17 +402,17 @@
         }
 
         if (result == null) {
-            result = new ArrayList<SubInfoRecord>();
+            result = new ArrayList<SubscriptionInfo>();
         }
         return result;
     }
 
     /**
-     * Get the SubInfoRecord(s) of the currently inserted SIM(s)
-     * @return Array list of currently inserted SubInfoRecord(s) maybe empty but not null
+     * Get the SubscriptionInfo(s) of the currently inserted SIM(s)
+     * @return Array list of currently inserted SubscriptionInfo(s) maybe empty but not null
      */
-    public static List<SubInfoRecord> getActiveSubInfoList() {
-        List<SubInfoRecord> result = null;
+    public static List<SubscriptionInfo> getActiveSubscriptionInfoList() {
+        List<SubscriptionInfo> result = null;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -390,7 +424,7 @@
         }
 
         if (result == null) {
-            result = new ArrayList<SubInfoRecord>();
+            result = new ArrayList<SubscriptionInfo>();
         }
         return result;
     }
@@ -400,8 +434,8 @@
      * @return all SIM count in database, include what was inserted before
      * @hide
      */
-    public static int getAllSubInfoCount() {
-        if (VDBG) logd("[getAllSubInfoCount]+");
+    public static int getAllSubscriptionInfoCount() {
+        if (VDBG) logd("[getAllSubscriptionInfoCount]+");
 
         int result = 0;
 
@@ -422,7 +456,7 @@
      * @return active SIM count
      * @hide
      */
-    public static int getActiveSubInfoCount() {
+    public static int getActiveSubscriptionInfoCount() {
         int result = 0;
 
         try {
@@ -438,19 +472,19 @@
     }
 
     /**
-     * Add a new SubInfoRecord to subinfo database if needed
+     * Add a new SubscriptionInfo to subinfo database if needed
      * @param iccId the IccId of the SIM card
      * @param slotId the slot which the SIM is inserted
      * @return the URL of the newly created row or the updated row
      * @hide
      */
-    public static Uri addSubInfoRecord(String iccId, int slotId) {
-        if (VDBG) logd("[addSubInfoRecord]+ iccId:" + iccId + " slotId:" + slotId);
+    public static Uri addSubscriptionInfoRecord(String iccId, int slotId) {
+        if (VDBG) logd("[addSubscriptionInfoRecord]+ iccId:" + iccId + " slotId:" + slotId);
         if (iccId == null) {
-            logd("[addSubInfoRecord]- null iccId");
+            logd("[addSubscriptionInfoRecord]- null iccId");
         }
         if (!isValidSlotId(slotId)) {
-            logd("[addSubInfoRecord]- invalid slotId");
+            logd("[addSubscriptionInfoRecord]- invalid slotId");
         }
 
         try {
@@ -500,7 +534,7 @@
     /**
      * Set display name by simInfo index
      * @param displayName the display name of SIM card
-     * @param subId the unique SubInfoRecord index in database
+     * @param subId the unique SubscriptionInfo index in database
      * @return the number of records updated
      * @hide
      */
@@ -511,7 +545,7 @@
     /**
      * Set display name by simInfo index with name source
      * @param displayName the display name of SIM card
-     * @param subId the unique SubInfoRecord index in database
+     * @param subId the unique SubscriptionInfo index in database
      * @param nameSource 0: NAME_SOURCE_DEFAULT_SOURCE, 1: NAME_SOURCE_SIM_SOURCE,
      *                   2: NAME_SOURCE_USER_INPUT, -1 NAME_SOURCE_UNDEFINED
      * @return the number of records updated or -1 if invalid subId
@@ -545,7 +579,7 @@
     /**
      * Set phone number by subId
      * @param number the phone number of the SIM
-     * @param subId the unique SubInfoRecord index in database
+     * @param subId the unique SubscriptionInfo index in database
      * @return the number of records updated
      * @hide
      */
@@ -573,7 +607,7 @@
     /**
      * Set data roaming by simInfo index
      * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming
-     * @param subId the unique SubInfoRecord index in database
+     * @param subId the unique SubscriptionInfo index in database
      * @return the number of records updated
      * @hide
      */
@@ -602,6 +636,7 @@
      * Get slotId associated with the subscription.
      * @return slotId as a positive integer or a negative value if an error either
      * SIM_NOT_INSERTED or INVALID_SLOT_ID.
+     * @hide
      */
     public static int getSlotId(int subId) {
         if (!isValidSubId(subId)) {
@@ -724,8 +759,8 @@
     }
 
     /** @hide */
-    public static SubInfoRecord getDefaultVoiceSubInfo() {
-        return getSubInfoForSubscriber(getDefaultVoiceSubId());
+    public static SubscriptionInfo getDefaultVoiceSubscriptionInfo() {
+        return getSubscriptionInfoForSubscriber(getDefaultVoiceSubId());
     }
 
     /** @hide */
@@ -735,6 +770,7 @@
 
     /**
      * @return subId of the DefaultSms subscription or the value INVALID_SUB_ID if an error.
+     * @hide
      */
     public static int getDefaultSmsSubId() {
         int subId = INVALID_SUB_ID;
@@ -766,8 +802,8 @@
     }
 
     /** @hide */
-    public static SubInfoRecord getDefaultSmsSubInfo() {
-        return getSubInfoForSubscriber(getDefaultSmsSubId());
+    public static SubscriptionInfo getDefaultSmsSubscriptionInfo() {
+        return getSubscriptionInfoForSubscriber(getDefaultSmsSubId());
     }
 
     /** @hide */
@@ -806,8 +842,8 @@
     }
 
     /** @hide */
-    public static SubInfoRecord getDefaultDataSubInfo() {
-        return getSubInfoForSubscriber(getDefaultDataSubId());
+    public static SubscriptionInfo getDefaultDataSubscriptionInfo() {
+        return getSubscriptionInfoForSubscriber(getDefaultDataSubId());
     }
 
     /** @hide */
@@ -816,7 +852,7 @@
     }
 
     /** @hide */
-    public static void clearSubInfo() {
+    public static void clearSubscriptionInfo() {
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
@@ -863,6 +899,7 @@
 
     /**
      * @return true if a valid subId else false
+     * @hide
      */
     public static boolean isValidSubId(int subId) {
         return subId > INVALID_SUB_ID ;
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 829620a..d82c492 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -17,41 +17,42 @@
 package com.android.internal.telephony;
 
 import android.app.PendingIntent;
-import android.telephony.SubInfoRecord;
+import android.telephony.SubscriptionInfo;
+import com.android.internal.telephony.ISubscriptionListener;
 
 interface ISub {
     /**
-     * Get the SubInfoRecord according to an index
-     * @param subId The unique SubInfoRecord index in database
-     * @return SubInfoRecord, maybe null
+     * Get the SubscriptionInfo according to an index
+     * @param subId The unique SubscriptionInfo index in database
+     * @return SubscriptionInfo, maybe null
      */
-    SubInfoRecord getSubInfoForSubscriber(int subId);
+    SubscriptionInfo getSubInfoForSubscriber(int subId);
 
     /**
-     * Get the SubInfoRecord according to an IccId
+     * Get the SubscriptionInfo according to an IccId
      * @param iccId the IccId of SIM card
-     * @return SubInfoRecord, maybe null
+     * @return SubscriptionInfo, maybe null
      */
-    List<SubInfoRecord> getSubInfoUsingIccId(String iccId);
+    List<SubscriptionInfo> getSubInfoUsingIccId(String iccId);
 
     /**
-     * Get the SubInfoRecord according to slotId
+     * Get the SubscriptionInfo according to slotId
      * @param slotId the slot which the SIM is inserted
-     * @return SubInfoRecord, maybe null
+     * @return SubscriptionInfo, maybe null
      */
-    List<SubInfoRecord> getSubInfoUsingSlotId(int slotId);
+    List<SubscriptionInfo> getSubInfoUsingSlotId(int slotId);
 
     /**
-     * Get all the SubInfoRecord(s) in subinfo database
+     * Get all the SubscriptionInfo(s) in subinfo database
      * @return Array list of all SubInfoRecords in database, include thsoe that were inserted before
      */
-    List<SubInfoRecord> getAllSubInfoList();
+    List<SubscriptionInfo> getAllSubInfoList();
 
     /**
-     * Get the SubInfoRecord(s) of the currently inserted SIM(s)
-     * @return Array list of currently inserted SubInfoRecord(s)
+     * Get the SubscriptionInfo(s) of the currently inserted SIM(s)
+     * @return Array list of currently inserted SubscriptionInfo(s)
      */
-    List<SubInfoRecord> getActiveSubInfoList();
+    List<SubscriptionInfo> getActiveSubInfoList();
 
     /**
      * Get the SUB count of all SUB(s) in subinfo database
@@ -66,7 +67,7 @@
     int getActiveSubInfoCount();
 
     /**
-     * Add a new SubInfoRecord to subinfo database if needed
+     * Add a new SubscriptionInfo to subinfo database if needed
      * @param iccId the IccId of the SIM card
      * @param slotId the slot which the SIM is inserted
      * @return the URL of the newly created row or the updated row
@@ -76,7 +77,7 @@
     /**
      * Set SIM icon tint color by simInfo index
      * @param tint the icon tint color of the SIM
-     * @param subId the unique SubInfoRecord index in database
+     * @param subId the unique SubscriptionInfo index in database
      * @return the number of records updated
      */
     int setIconTint(int tint, int subId);
@@ -84,7 +85,7 @@
     /**
      * Set display name by simInfo index
      * @param displayName the display name of SIM card
-     * @param subId the unique SubInfoRecord index in database
+     * @param subId the unique SubscriptionInfo index in database
      * @return the number of records updated
      */
     int setDisplayName(String displayName, int subId);
@@ -92,7 +93,7 @@
     /**
      * Set display name by simInfo index with name source
      * @param displayName the display name of SIM card
-     * @param subId the unique SubInfoRecord index in database
+     * @param subId the unique SubscriptionInfo index in database
      * @param nameSource, 0: DEFAULT_SOURCE, 1: SIM_SOURCE, 2: USER_INPUT
      * @return the number of records updated
      */
@@ -101,7 +102,7 @@
     /**
      * Set phone number by subId
      * @param number the phone number of the SIM
-     * @param subId the unique SubInfoRecord index in database
+     * @param subId the unique SubscriptionInfo index in database
      * @return the number of records updated
      */
     int setDisplayNumber(String number, int subId);
@@ -109,7 +110,7 @@
     /**
      * Set data roaming by simInfo index
      * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming
-     * @param subId the unique SubInfoRecord index in database
+     * @param subId the unique SubscriptionInfo index in database
      * @return the number of records updated
      */
     int setDataRoaming(int roaming, int subId);
diff --git a/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl b/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
new file mode 100644
index 0000000..4ccdea5
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ISubscriptionListener.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.telephony.SubscriptionInfo;
+
+oneway interface ISubscriptionListener {
+    void onSubscriptionInfoChanged();
+}
+
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index ee3f8b0..1a1f8fe 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -27,8 +27,11 @@
 import android.telephony.CellInfo;
 import android.telephony.VoLteServiceState;
 import com.android.internal.telephony.IPhoneStateListener;
+import com.android.internal.telephony.ISubscriptionListener;
 
 interface ITelephonyRegistry {
+    void registerSubscriptionListener(String pkg, ISubscriptionListener callback, int events);
+    void unregisterSubscriptionListener(String pkg, ISubscriptionListener callback);
     void listen(String pkg, IPhoneStateListener callback, int events, boolean notifyNow);
     void listenForSubscriber(in int subId, String pkg, IPhoneStateListener callback, int events,
             boolean notifyNow);
@@ -63,4 +66,5 @@
     void notifyDataConnectionRealTimeInfo(in DataConnectionRealTimeInfo dcRtInfo);
     void notifyVoLteServiceStateChanged(in VoLteServiceState lteState);
     void notifyOemHookRawEventForSubscriber(in int subId, in byte[] rawData);
+    void notifySubscriptionInfoChanged();
 }
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index d05e7d1..c67e5d7 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -312,27 +312,7 @@
     public static final String EXTRA_SPN        = "spn";
 
     /**
-     * <p>Broadcast Action: It indicates one column of a siminfo record has been changed
-     * The intent will have the following extra values:</p>
-     * <ul>
-     *   <li><em>columnName</em> - The siminfo column that is updated.</li>
-     *   <li><em>stringContent</em> - The string value of the updated column.</li>
-     *   <li><em>intContent</em> - The int value of the updated column.</li>
-     * </ul>
-     * <p class="note">This is a protected intent that can only be sent
-     * by the system.
-     */
-    public static final String ACTION_SIMINFO_CONTENT_CHANGE
-            = "android.intent.action.ACTION_SIMINFO_CONTENT_CHANGE";
-
-    /**
      * <p>Broadcast Action: It indicates one column of a subinfo record has been changed
-     * The intent will have the following extra values:</p>
-     * <ul>
-     *   <li><em>columnName</em> - The siminfo column that is updated.</li>
-     *   <li><em>stringContent</em> - The string value of the updated column.</li>
-     *   <li><em>intContent</em> - The int value of the updated column.</li>
-     * </ul>
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
@@ -340,28 +320,14 @@
             = "android.intent.action.ACTION_SUBINFO_CONTENT_CHANGE";
 
     /**
-     * <p>Broadcast Action: It indicates siminfo update is completed when SIM inserted state change
-     * The intent will have the following extra values:</p>
-     * <p class="note">This is a protected intent that can only be sent
-     * by the system.
-     */
-    public static final String ACTION_SIMINFO_UPDATED
-            = "android.intent.action.ACTION_SIMINFO_UPDATED";
-
-    /**
      * <p>Broadcast Action: It indicates subinfo record update is completed
      * when SIM inserted state change
-     * The intent will have the following extra values:</p>
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
     public static final String ACTION_SUBINFO_RECORD_UPDATED
             = "android.intent.action.ACTION_SUBINFO_RECORD_UPDATED";
 
-    public static final String EXTRA_COLUMN_NAME = "columnName";
-    public static final String EXTRA_INT_CONTENT = "intContent";
-    public static final String EXTRA_STRING_CONTENT = "stringContent";
-
     /**
      * Broadcast Action: The default subscription has changed.  This has the following
      * extra values:</p>