Update SubscriptionManager API as per API council.

bug: 17575308
Change-Id: Ib39a60e4f75981a466e9d606ec627756efad018d
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 86aa516..8c3c102 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);
     }