OSDN Git Service

Additional changes to SubscriptionManager API as per API council.
authorWink Saville <wink@google.com>
Thu, 20 Nov 2014 00:03:09 +0000 (16:03 -0800)
committerWink Saville <wink@google.com>
Thu, 20 Nov 2014 00:03:09 +0000 (16:03 -0800)
bug: 17575308
Change-Id: I7773965094510999bfce8fc6b2b31ba6ce496653

15 files changed:
Android.mk
api/current.txt
core/java/android/app/ContextImpl.java
core/java/android/content/Context.java
core/java/android/provider/CallLog.java
services/core/java/com/android/server/NetworkManagementService.java
services/core/java/com/android/server/TelephonyRegistry.java
services/core/java/com/android/server/location/GpsLocationProvider.java
telephony/java/android/telephony/PhoneStateListener.java
telephony/java/android/telephony/SubscriptionListener.java [deleted file]
telephony/java/android/telephony/SubscriptionManager.java
telephony/java/android/telephony/TelephonyManager.java
telephony/java/com/android/internal/telephony/IOnSubscriptionsChangedListener.aidl [new file with mode: 0644]
telephony/java/com/android/internal/telephony/ISub.aidl
telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl

index a596ee7..8b16326 100644 (file)
@@ -372,8 +372,8 @@ LOCAL_SRC_FILES += \
        telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
        telephony/java/com/android/internal/telephony/ITelephony.aidl \
        telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
+       telephony/java/com/android/internal/telephony/IOnSubscriptionsChangedListener.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 \
index b5055eb..527fc54 100644 (file)
@@ -7268,6 +7268,7 @@ package android.content {
     field public static final java.lang.String STORAGE_SERVICE = "storage";
     field public static final java.lang.String TELECOM_SERVICE = "telecom";
     field public static final java.lang.String TELEPHONY_SERVICE = "phone";
+    field public static final java.lang.String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service";
     field public static final java.lang.String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
     field public static final java.lang.String TV_INPUT_SERVICE = "tv_input";
     field public static final java.lang.String UI_MODE_SERVICE = "uimode";
@@ -25574,7 +25575,7 @@ package android.provider {
     field public static final java.lang.String STATUS = "st";
     field public static final java.lang.String SUBJECT = "sub";
     field public static final java.lang.String SUBJECT_CHARSET = "sub_cs";
-    field public static final java.lang.String SUB_ID = "sub_id";
+    field public static final java.lang.String SUBSCRIPTION_ID = "sub_id";
     field public static final java.lang.String TEXT_ONLY = "text_only";
     field public static final java.lang.String THREAD_ID = "thread_id";
     field public static final java.lang.String TRANSACTION_ID = "tr_id";
@@ -25607,7 +25608,7 @@ package android.provider {
     field public static final java.lang.String PROXY = "proxy";
     field public static final java.lang.String ROAMING_PROTOCOL = "roaming_protocol";
     field public static final java.lang.String SERVER = "server";
-    field public static final java.lang.String SUB_ID = "sub_id";
+    field public static final java.lang.String SUBSCRIPTION_ID = "sub_id";
     field public static final java.lang.String TYPE = "type";
     field public static final java.lang.String USER = "user";
   }
@@ -25708,7 +25709,7 @@ package android.provider {
     field public static final java.lang.String MSG_TYPE = "msg_type";
     field public static final java.lang.String PROTO_TYPE = "proto_type";
     field public static final java.lang.String RETRY_INDEX = "retry_index";
-    field public static final java.lang.String SUB_ID = "pending_sub_id";
+    field public static final java.lang.String SUBSCRIPTION_ID = "pending_sub_id";
   }
 
   public static final class Telephony.Sms implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
@@ -25794,7 +25795,7 @@ package android.provider {
     field public static final int STATUS_NONE = -1; // 0xffffffff
     field public static final int STATUS_PENDING = 32; // 0x20
     field public static final java.lang.String SUBJECT = "subject";
-    field public static final java.lang.String SUB_ID = "sub_id";
+    field public static final java.lang.String SUBSCRIPTION_ID = "sub_id";
     field public static final java.lang.String THREAD_ID = "thread_id";
     field public static final java.lang.String TYPE = "type";
   }
@@ -28647,20 +28648,19 @@ package android.telephony {
     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 {
+    method public static android.telephony.SubscriptionManager from(android.content.Context);
+    method public android.telephony.SubscriptionInfo getActiveSubscriptionInfo(int);
+    method public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int);
+    method public java.util.List<android.telephony.SubscriptionInfo> getActiveSubscriptionInfoList();
+    method public void registerOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
+    method public void unregisterOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
+    field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
   }
 
-  public class SubscriptionManager implements android.provider.BaseColumns {
-    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
+  public static class SubscriptionManager.OnSubscriptionsChangedListener {
+    ctor public SubscriptionManager.OnSubscriptionsChangedListener();
+    method public void onSubscriptionsChanged();
   }
 
   public class TelephonyManager {
index 7fafc38..68981f1 100644 (file)
@@ -20,9 +20,9 @@ import android.app.usage.IUsageStatsManager;
 import android.app.usage.UsageStatsManager;
 import android.appwidget.AppWidgetManager;
 import android.os.Build;
-
 import android.service.persistentdata.IPersistentDataBlockService;
 import android.service.persistentdata.PersistentDataBlockManager;
+
 import com.android.internal.appwidget.IAppWidgetService;
 import com.android.internal.policy.PolicyManager;
 import com.android.internal.util.Preconditions;
@@ -125,6 +125,7 @@ import android.print.PrintManager;
 import android.service.fingerprint.IFingerprintService;
 import android.service.fingerprint.FingerprintManager;
 import android.telecom.TelecomManager;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.content.ClipboardManager;
 import android.util.AndroidRuntimeException;
@@ -561,6 +562,11 @@ class ContextImpl extends Context {
                     return new TelephonyManager(ctx.getOuterContext());
                 }});
 
+        registerService(TELEPHONY_SUBSCRIPTION_SERVICE, new ServiceFetcher() {
+            public Object createService(ContextImpl ctx) {
+                return new SubscriptionManager(ctx.getOuterContext());
+            }});
+
         registerService(TELECOM_SERVICE, new ServiceFetcher() {
                 public Object createService(ContextImpl ctx) {
                     return new TelecomManager(ctx.getOuterContext());
index c9b7d0a..4048ac1 100644 (file)
@@ -2244,6 +2244,8 @@ public abstract class Context {
      * @see android.media.MediaRouter
      * @see #TELEPHONY_SERVICE
      * @see android.telephony.TelephonyManager
+     * @see #TELEPHONY_SUBSCRIPTION_SERVICE
+     * @see android.telephony.SubscriptionManager
      * @see #INPUT_METHOD_SERVICE
      * @see android.view.inputmethod.InputMethodManager
      * @see #UI_MODE_SERVICE
@@ -2588,6 +2590,16 @@ public abstract class Context {
 
     /**
      * Use with {@link #getSystemService} to retrieve a
+     * {@link android.telephony.SubscriptionManager} for handling management the
+     * telephony subscriptions of the device.
+     *
+     * @see #getSystemService
+     * @see android.telephony.SubscriptionManager
+     */
+    public static final String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service";
+
+    /**
+     * Use with {@link #getSystemService} to retrieve a
      * {@link android.telecom.TelecomManager} to manage telecom-related features
      * of the device.
      *
index 3ec45e9..f023df7 100644 (file)
@@ -387,7 +387,6 @@ public class CallLog {
         public static Uri addCall(CallerInfo ci, Context context, String number,
                 int presentation, int callType, int features, PhoneAccountHandle accountHandle,
                 long start, int duration, Long dataUsage) {
-            // FIXME using -1 as subId instead of SubscriptionManager.INVALID_SUB_ID
             return addCall(ci, context, number, presentation, callType, features, accountHandle,
                     start, duration, dataUsage, false);
         }
index 0f033d7..5fe0d1c 100644 (file)
@@ -239,7 +239,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
 
         mDaemonHandler = new Handler(FgThread.get().getLooper());
 
-        mPhoneStateListener = new PhoneStateListener(SubscriptionManager.DEFAULT_SUB_ID,
+        mPhoneStateListener = new PhoneStateListener(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
                 mDaemonHandler.getLooper()) {
             @Override
             public void onDataConnectionRealTimeInfoChanged(
index 2ed021a..9b5b38d 100644 (file)
@@ -34,8 +34,6 @@ import android.os.UserHandle;
 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;
@@ -43,7 +41,6 @@ import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.CellInfo;
 import android.telephony.VoLteServiceState;
-import android.telephony.TelephonyManager;
 import android.telephony.DisconnectCause;
 import android.telephony.PreciseCallState;
 import android.telephony.PreciseDataConnectionState;
@@ -52,13 +49,12 @@ import android.text.TextUtils;
 import android.text.format.Time;
 
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.List;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
 import com.android.internal.app.IBatteryStats;
-import com.android.internal.telephony.ISubscriptionListener;
+import com.android.internal.telephony.IOnSubscriptionsChangedListener;
 import com.android.internal.telephony.ITelephonyRegistry;
 import com.android.internal.telephony.IPhoneStateListener;
 import com.android.internal.telephony.DefaultPhoneNotifier;
@@ -93,28 +89,29 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
         IBinder binder;
 
         IPhoneStateListener callback;
-        ISubscriptionListener subscriptionListenerCallback;
+        IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback;
 
         int callerUid;
 
         int events;
 
-        int subId = SubscriptionManager.INVALID_SUB_ID;
+        int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
-        int phoneId = SubscriptionManager.INVALID_PHONE_ID;
+        int phoneId = SubscriptionManager.INVALID_PHONE_INDEX;
 
         boolean matchPhoneStateListenerEvent(int events) {
             return (callback != null) && ((events & this.events) != 0);
         }
 
-        boolean matchSubscriptionListenerEvent(int events) {
-            return (subscriptionListenerCallback != null) && ((events & this.events) != 0);
+        boolean matchOnSubscriptionsChangedListener() {
+            return (onSubscriptionsChangedListenerCallback != null);
         }
 
         @Override
         public String toString() {
             return "{pkgForDebug=" + pkgForDebug + " binder=" + binder + " callback=" + callback
-                    + " subscriptionListenererCallback=" + subscriptionListenerCallback
+                    + " onSubscriptionsChangedListenererCallback="
+                                            + onSubscriptionsChangedListenerCallback
                     + " callerUid=" + callerUid + " subId=" + subId + " phoneId=" + phoneId
                     + " events=" + Integer.toHexString(events) + "}";
         }
@@ -128,6 +125,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
 
     private final IBatteryStats mBatteryStats;
 
+    private boolean hasNotifySubscriptionInfoChangedOccurred = false;
+
     private int mNumPhones;
 
     private int[] mCallState;
@@ -168,9 +167,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
 
     private VoLteServiceState mVoLteServiceState = new VoLteServiceState();
 
-    private int mDefaultSubId = SubscriptionManager.INVALID_SUB_ID;
+    private int mDefaultSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
-    private int mDefaultPhoneId = SubscriptionManager.INVALID_PHONE_ID;
+    private int mDefaultPhoneId = SubscriptionManager.INVALID_PHONE_INDEX;
 
     private DataConnectionRealTimeInfo mDcRtInfo = new DataConnectionRealTimeInfo();
 
@@ -227,7 +226,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
                     //possible missed notify callback
                     synchronized (mRecords) {
                         for (Record r : mRecords) {
-                            if(r.subId == SubscriptionManager.DEFAULT_SUB_ID) {
+                            if(r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
                                 checkPossibleMissNotify(r, newDefaultPhoneId);
                             }
                         }
@@ -339,90 +338,85 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
     }
 
     @Override
-    public void registerSubscriptionListener(String pkgForDebug, ISubscriptionListener callback,
-            int events) {
+    public void registerOnSubscriptionsChangedListener(String pkgForDebug,
+            IOnSubscriptionsChangedListener callback) {
         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
+            log("listen oscl: E pkg=" + pkgForDebug + " myUid=" + myUid
+                + " callerUid="  + callerUid + " callback=" + callback
                 + " callback.asBinder=" + callback.asBinder());
         }
 
-        if (events != 0) {
-            /* Checks permission and throws Security exception */
-            checkSubscriptionListenerPermission(events);
-            Record r = null;
+        /* Checks permission and throws Security exception */
+        checkOnSubscriptionsChangedListenerPermission();
+        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;
-                        }
+        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);
                 }
+                r = new Record();
+                r.binder = b;
+                mRecords.add(r);
+                if (DBG) log("listen oscl: add new record");
             }
 
-            // Always notify when a listen is established.
-            if (r.matchSubscriptionListenerEvent(
-                    SubscriptionListener.LISTEN_SUBSCRIPTION_INFO_LIST_CHANGED)) {
+            r.onSubscriptionsChangedListenerCallback = callback;
+            r.pkgForDebug = pkgForDebug;
+            r.callerUid = callerUid;
+            r.events = 0;
+            if (DBG) {
+                log("listen oscl:  Register r=" + r);
+            }
+            // Always notify when registration occurs if there has been a notification.
+            if (hasNotifySubscriptionInfoChangedOccurred) {
                 try {
-                    if (VDBG) log("listen sl: send to r=" + r);
-                    r.subscriptionListenerCallback.onSubscriptionInfoChanged();
-                    if (VDBG) log("listen sl: sent to r=" + r);
+                    if (VDBG) log("listen oscl: send to r=" + r);
+                    r.onSubscriptionsChangedListenerCallback.onSubscriptionsChanged();
+                    if (VDBG) log("listen oscl: sent to r=" + r);
                 } catch (RemoteException e) {
-                    if (VDBG) log("listen sl: remote exception sending to r=" + r + " e=" + e);
+                    if (VDBG) log("listen oscl: remote exception sending to r=" + r + " e=" + e);
                     remove(r.binder);
                 }
+            } else {
+                log("listen oscl: hasNotifySubscriptionInfoChangedOccurred==false no callback");
             }
-        } 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");
+    public void unregisterOnSubscriptionsChangedListener(String pkgForDebug,
+            IOnSubscriptionsChangedListener callback) {
+        if (DBG) log("listen oscl: Unregister");
         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);
-        }
+    private void checkOnSubscriptionsChangedListenerPermission() {
+        mContext.enforceCallingOrSelfPermission(
+                SubscriptionManager.OnSubscriptionsChangedListener
+                    .PERMISSION_ON_SUBSCRIPTIONS_CHANGED, null);
     }
 
     @Override
     public void notifySubscriptionInfoChanged() {
         if (VDBG) log("notifySubscriptionInfoChanged:");
         synchronized (mRecords) {
+            hasNotifySubscriptionInfoChangedOccurred = true;
             mRemoveList.clear();
             for (Record r : mRecords) {
-                if (r.matchSubscriptionListenerEvent(
-                        SubscriptionListener.LISTEN_SUBSCRIPTION_INFO_LIST_CHANGED)) {
+                if (r.matchOnSubscriptionsChangedListener()) {
                     try {
-                        if (VDBG) log("notifySubscriptionInfoChanged: send to r=" + r);
-                        r.subscriptionListenerCallback.onSubscriptionInfoChanged();
-                        if (VDBG) log("notifySubscriptionInfoChanged: sent to r=" + r);
+                        if (VDBG) log("notifySubscriptionInfoChanged: call osc to r=" + r);
+                        r.onSubscriptionsChangedListenerCallback.onSubscriptionsChanged();
+                        if (VDBG) log("notifySubscriptionInfoChanged: call osc to r=" + r);
                     } catch (RemoteException ex) {
                         if (VDBG) log("notifySubscriptionInfoChanged: RemoteException r=" + r);
                         mRemoveList.add(r.binder);
@@ -436,8 +430,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
     @Override
     public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
             boolean notifyNow) {
-        listenForSubscriber(SubscriptionManager.DEFAULT_SUB_ID, pkgForDebug, callback, events,
-            notifyNow);
+        listenForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, pkgForDebug, callback,
+                events, notifyNow);
     }
 
     @Override
@@ -483,7 +477,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
                 // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
                 // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
                 if (!SubscriptionManager.isValidSubId(subId)) {
-                    r.subId = SubscriptionManager.DEFAULT_SUB_ID;
+                    r.subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
                  } else {//APP specify subID
                     r.subId = subId;
                 }
@@ -642,7 +636,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
         synchronized (mRecords) {
             for (Record r : mRecords) {
                 if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_CALL_STATE) &&
-                        (r.subId == SubscriptionManager.DEFAULT_SUB_ID)) {
+                        (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
                     try {
                         r.callback.onCallStateChanged(state, incomingNumber);
                     } catch (RemoteException ex) {
@@ -652,7 +646,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
             }
             handleRemoveListLocked();
         }
-        broadcastCallStateChanged(state, incomingNumber, SubscriptionManager.DEFAULT_SUB_ID);
+        broadcastCallStateChanged(state, incomingNumber,
+                SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
     }
 
     public void notifyCallStateForSubscriber(int subId, int state, String incomingNumber) {
@@ -671,7 +666,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_CALL_STATE) &&
                             (r.subId == subId) &&
-                            (r.subId != SubscriptionManager.DEFAULT_SUB_ID)) {
+                            (r.subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
                         try {
                             r.callback.onCallStateChanged(state, incomingNumber);
                         } catch (RemoteException ex) {
@@ -728,7 +723,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
     }
 
     public void notifySignalStrength(SignalStrength signalStrength) {
-        notifySignalStrengthForSubscriber(SubscriptionManager.DEFAULT_SUB_ID, signalStrength);
+        notifySignalStrengthForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+                signalStrength);
     }
 
     public void notifySignalStrengthForSubscriber(int subId, SignalStrength signalStrength) {
@@ -789,7 +785,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
     }
 
     public void notifyCellInfo(List<CellInfo> cellInfo) {
-         notifyCellInfoForSubscriber(SubscriptionManager.DEFAULT_SUB_ID, cellInfo);
+         notifyCellInfoForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, cellInfo);
     }
 
     public void notifyCellInfoForSubscriber(int subId, List<CellInfo> cellInfo) {
@@ -877,7 +873,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
     }
 
     public void notifyCallForwardingChanged(boolean cfi) {
-        notifyCallForwardingChangedForSubscriber(SubscriptionManager.DEFAULT_SUB_ID, cfi);
+        notifyCallForwardingChangedForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, cfi);
     }
 
     public void notifyCallForwardingChangedForSubscriber(int subId, boolean cfi) {
@@ -909,7 +905,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
     }
 
     public void notifyDataActivity(int state) {
-        notifyDataActivityForSubscriber(SubscriptionManager.DEFAULT_SUB_ID, state);
+        notifyDataActivityForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, state);
     }
 
     public void notifyDataActivityForSubscriber(int subId, int state) {
@@ -918,13 +914,15 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
         }
         synchronized (mRecords) {
             int phoneId = SubscriptionManager.getPhoneId(subId);
-            mDataActivity[phoneId] = state;
-            for (Record r : mRecords) {
-                if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_DATA_ACTIVITY)) {
-                    try {
-                        r.callback.onDataActivity(state);
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
+            if (validatePhoneId(phoneId)) {
+                mDataActivity[phoneId] = state;
+                for (Record r : mRecords) {
+                    if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_DATA_ACTIVITY)) {
+                        try {
+                            r.callback.onDataActivity(state);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
                     }
                 }
             }
@@ -935,7 +933,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
     public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
             String reason, String apn, String apnType, LinkProperties linkProperties,
             NetworkCapabilities networkCapabilities, int networkType, boolean roaming) {
-        notifyDataConnectionForSubscriber(SubscriptionManager.DEFAULT_SUB_ID, state,
+        notifyDataConnectionForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, state,
             isDataConnectivityPossible,reason, apn, apnType, linkProperties,
             networkCapabilities, networkType, roaming);
     }
@@ -956,67 +954,69 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
         }
         synchronized (mRecords) {
             int phoneId = SubscriptionManager.getPhoneId(subId);
-            boolean modified = false;
-            if (state == TelephonyManager.DATA_CONNECTED) {
-                if (!mConnectedApns.contains(apnType)) {
-                    mConnectedApns.add(apnType);
-                    if (mDataConnectionState[phoneId] != state) {
-                        mDataConnectionState[phoneId] = state;
-                        modified = true;
+            if (validatePhoneId(phoneId)) {
+                boolean modified = false;
+                if (state == TelephonyManager.DATA_CONNECTED) {
+                    if (!mConnectedApns.contains(apnType)) {
+                        mConnectedApns.add(apnType);
+                        if (mDataConnectionState[phoneId] != state) {
+                            mDataConnectionState[phoneId] = state;
+                            modified = true;
+                        }
                     }
-                }
-            } else {
-                if (mConnectedApns.remove(apnType)) {
-                    if (mConnectedApns.isEmpty()) {
-                        mDataConnectionState[phoneId] = state;
-                        modified = true;
-                    } else {
-                        // leave mDataConnectionState as is and
-                        // send out the new status for the APN in question.
+                } else {
+                    if (mConnectedApns.remove(apnType)) {
+                        if (mConnectedApns.isEmpty()) {
+                            mDataConnectionState[phoneId] = state;
+                            modified = true;
+                        } else {
+                            // leave mDataConnectionState as is and
+                            // send out the new status for the APN in question.
+                        }
                     }
                 }
-            }
-            mDataConnectionPossible[phoneId] = isDataConnectivityPossible;
-            mDataConnectionReason[phoneId] = reason;
-            mDataConnectionLinkProperties[phoneId] = linkProperties;
-            mDataConnectionNetworkCapabilities[phoneId] = networkCapabilities;
-            if (mDataConnectionNetworkType[phoneId] != networkType) {
-                mDataConnectionNetworkType[phoneId] = networkType;
-                // need to tell registered listeners about the new network type
-                modified = true;
-            }
-            if (modified) {
-                if (DBG) {
-                    log("onDataConnectionStateChanged(" + mDataConnectionState[phoneId]
-                        + ", " + mDataConnectionNetworkType[phoneId] + ")");
+                mDataConnectionPossible[phoneId] = isDataConnectivityPossible;
+                mDataConnectionReason[phoneId] = reason;
+                mDataConnectionLinkProperties[phoneId] = linkProperties;
+                mDataConnectionNetworkCapabilities[phoneId] = networkCapabilities;
+                if (mDataConnectionNetworkType[phoneId] != networkType) {
+                    mDataConnectionNetworkType[phoneId] = networkType;
+                    // need to tell registered listeners about the new network type
+                    modified = true;
+                }
+                if (modified) {
+                    if (DBG) {
+                        log("onDataConnectionStateChanged(" + mDataConnectionState[phoneId]
+                            + ", " + mDataConnectionNetworkType[phoneId] + ")");
+                    }
+                    for (Record r : mRecords) {
+                        if (r.matchPhoneStateListenerEvent(
+                                PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) &&
+                                idMatch(r.subId, subId, phoneId)) {
+                            try {
+                                log("Notify data connection state changed on sub: " +
+                                        subId);
+                                r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
+                                        mDataConnectionNetworkType[phoneId]);
+                            } catch (RemoteException ex) {
+                                mRemoveList.add(r.binder);
+                            }
+                        }
+                    }
+                    handleRemoveListLocked();
                 }
+                mPreciseDataConnectionState = new PreciseDataConnectionState(state, networkType,
+                        apnType, apn, reason, linkProperties, "");
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) &&
-                            idMatch(r.subId, subId, phoneId)) {
+                            PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)) {
                         try {
-                            log("Notify data connection state changed on sub: " +
-                                    subId);
-                            r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
-                                    mDataConnectionNetworkType[phoneId]);
+                            r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
                         } catch (RemoteException ex) {
                             mRemoveList.add(r.binder);
                         }
                     }
                 }
-                handleRemoveListLocked();
-            }
-            mPreciseDataConnectionState = new PreciseDataConnectionState(state, networkType,
-                    apnType, apn, reason, linkProperties, "");
-            for (Record r : mRecords) {
-                if (r.matchPhoneStateListenerEvent(
-                        PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)) {
-                    try {
-                        r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
-                    }
-                }
             }
             handleRemoveListLocked();
         }
@@ -1027,7 +1027,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
     }
 
     public void notifyDataConnectionFailed(String reason, String apnType) {
-         notifyDataConnectionFailedForSubscriber(SubscriptionManager.DEFAULT_SUB_ID,
+         notifyDataConnectionFailedForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
                  reason, apnType);
     }
 
@@ -1062,7 +1062,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
     }
 
     public void notifyCellLocation(Bundle cellLocation) {
-         notifyCellLocationForSubscriber(SubscriptionManager.DEFAULT_SUB_ID, cellLocation);
+         notifyCellLocationForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, cellLocation);
     }
 
     public void notifyCellLocationForSubscriber(int subId, Bundle cellLocation) {
@@ -1226,7 +1226,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
                 if ((r.matchPhoneStateListenerEvent(
                         PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT)) &&
                         ((r.subId == subId) ||
-                        (r.subId == SubscriptionManager.DEFAULT_SUB_ID))) {
+                        (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID))) {
                     try {
                         r.callback.onOemHookRawEvent(rawData);
                     } catch (RemoteException ex) {
@@ -1399,14 +1399,17 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
     }
 
     private void broadcastPreciseDataConnectionStateChanged(int state, int networkType,
-            String apnType, String apn, String reason, LinkProperties linkProperties, String failCause) {
+            String apnType, String apn, String reason, LinkProperties linkProperties,
+            String failCause) {
         Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED);
         intent.putExtra(PhoneConstants.STATE_KEY, state);
         intent.putExtra(PhoneConstants.DATA_NETWORK_TYPE_KEY, networkType);
         if (reason != null) intent.putExtra(PhoneConstants.STATE_CHANGE_REASON_KEY, reason);
         if (apnType != null) intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
         if (apn != null) intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
-        if (linkProperties != null) intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties);
+        if (linkProperties != null) {
+            intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY,linkProperties);
+        }
         if (failCause != null) intent.putExtra(PhoneConstants.DATA_FAILURE_CAUSE_KEY, failCause);
 
         mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
@@ -1506,7 +1509,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
 
         @Override
         public String toString() {
-            return mS + " Time " + mTime.toString() + " mSubId " + mSubId + " mPhoneId " + mPhoneId + "  mState " + mState;
+            return mS + " Time " + mTime.toString() + " mSubId " + mSubId + " mPhoneId "
+                    + mPhoneId + "  mState " + mState;
         }
     }
 
@@ -1550,7 +1554,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
     }
 
     boolean idMatch(int rSubId, int subId, int phoneId) {
-        if(rSubId == SubscriptionManager.DEFAULT_SUB_ID) {
+        if(rSubId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
             if(subId < 0) {
                 // Invalid case, we need compare phoneId with default one.
                 return (mDefaultPhoneId == phoneId);
index 8c3c102..c960c07 100644 (file)
@@ -73,8 +73,8 @@ 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.SubscriptionManager.OnSubscriptionsChangedListener;
 import android.telephony.TelephonyManager;
 import android.telephony.gsm.GsmCellLocation;
 import android.text.TextUtils;
@@ -462,9 +462,10 @@ public class GpsLocationProvider implements LocationProviderInterface {
         }
     };
 
-    private final SubscriptionListener mSubscriptionListener = new SubscriptionListener() {
+    private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
+            new OnSubscriptionsChangedListener() {
         @Override
-        public void onSubscriptionInfoChanged() {
+        public void onSubscriptionsChanged() {
             subscriptionOrSimChanged(mContext);
         }
     };
@@ -640,14 +641,14 @@ public class GpsLocationProvider implements LocationProviderInterface {
                                                 mSuplEsEnabled);
 
         // TODO: When this object "finishes" we should unregister by invoking
-        // SubscriptionManager.unregister(mContext, mSubscriptionListener);
+        // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener);
         // 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);
+        // to invoke onSubscriptionsChanged the first time.
+        SubscriptionManager.from(mContext)
+            .registerOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
 
         // construct handler, listen for events
         mHandler = new ProviderHandler(looper);
index 2f1a8da..8f4a92b 100644 (file)
@@ -227,7 +227,7 @@ public class PhoneStateListener {
      * @hide
      */
     /** @hide */
-    protected int mSubId = SubscriptionManager.INVALID_SUB_ID;
+    protected int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
     private final Handler mHandler;
 
@@ -237,7 +237,7 @@ public class PhoneStateListener {
      * own non-null looper use PhoneStateListener(Looper looper) below.
      */
     public PhoneStateListener() {
-        this(SubscriptionManager.DEFAULT_SUB_ID, Looper.myLooper());
+        this(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, Looper.myLooper());
     }
 
     /**
@@ -246,7 +246,7 @@ public class PhoneStateListener {
      * @hide
      */
     public PhoneStateListener(Looper looper) {
-        this(SubscriptionManager.DEFAULT_SUB_ID, looper);
+        this(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, looper);
     }
 
     /**
diff --git a/telephony/java/android/telephony/SubscriptionListener.java b/telephony/java/android/telephony/SubscriptionListener.java
deleted file mode 100644 (file)
index 5c65333..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * 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);
-    }
-}
index 78ab687..43ce51f 100644 (file)
@@ -21,12 +21,14 @@ import android.annotation.SdkConstant.SdkConstantType;
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
-import android.provider.BaseColumns;
 import android.telephony.Rlog;
+import android.os.Handler;
+import android.os.Message;
 import android.os.ServiceManager;
 import android.os.RemoteException;
 
 import com.android.internal.telephony.ISub;
+import com.android.internal.telephony.IOnSubscriptionsChangedListener;
 import com.android.internal.telephony.ITelephonyRegistry;
 import com.android.internal.telephony.PhoneConstants;
 
@@ -36,62 +38,79 @@ import java.util.List;
 /**
  * SubscriptionManager is the application interface to SubscriptionController
  * and provides information about the current Telephony Subscriptions.
- *
- * The android.Manifest.permission.READ_PHONE_STATE to retrieve the information, except
- * getActiveSubIdList and getActiveSubIdCount for which no permission is needed.
+ * * <p>
+ * You do not instantiate this class directly; instead, you retrieve
+ * a reference to an instance through {@link #from}.
+ * <p>
+ * All SDK public methods require android.Manifest.permission.READ_PHONE_STATE.
  */
-public class SubscriptionManager implements BaseColumns {
-    private static final String LOG_TAG = "SUB";
+public class SubscriptionManager {
+    private static final String LOG_TAG = "SubscriptionManager";
     private static final boolean DBG = true;
     private static final boolean VDBG = false;
 
     /** An invalid subscription identifier */
-    public static final int INVALID_SUB_ID = -1000;
+    public static final int INVALID_SUBSCRIPTION_ID = -1;
+
+    /** Base value for Dummy SUBSCRIPTION_ID's. */
+    /** FIXME: Remove DummySubId's, but for now have them map just below INVALID_SUBSCRIPTION_ID
+    /** @hide */
+    public static final int DUMMY_SUBSCRIPTION_ID_BASE = INVALID_SUBSCRIPTION_ID - 1;
 
     /** An invalid phone identifier */
     /** @hide */
-    public static final int INVALID_PHONE_ID = -1;
+    public static final int INVALID_PHONE_INDEX = -1;
 
     /** An invalid slot identifier */
     /** @hide */
-    public static final int INVALID_SLOT_ID = -1;
+    public static final int INVALID_SIM_SLOT_INDEX = -1;
 
     /** Indicates the caller wants the default sub id. */
     /** @hide */
-    public static final int DEFAULT_SUB_ID = Integer.MAX_VALUE;
+    public static final int DEFAULT_SUBSCRIPTION_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 phone id.
+     * Used in SubscriptionController and PhoneBase but do we really need it???
+     * @hide
+     */
+    public static final int DEFAULT_PHONE_INDEX = Integer.MAX_VALUE;
 
-    /** Indicates the caller wants the default slot id. */
+    /** Indicates the caller wants the default slot id. NOT used remove? */
     /** @hide */
-    public static final int DEFAULT_SLOT_ID = Integer.MAX_VALUE;
+    public static final int DEFAULT_SIM_SLOT_INDEX = Integer.MAX_VALUE;
 
     /** Minimum possible subid that represents a subscription */
     /** @hide */
-    public static final int MIN_SUB_ID_VALUE = 0;
+    public static final int MIN_SUBSCRIPTION_ID_VALUE = 0;
 
     /** Maximum possible subid that represents a subscription */
     /** @hide */
-    public static final int MAX_SUB_ID_VALUE = DEFAULT_SUB_ID - 1;
-
+    public static final int MAX_SUBSCRIPTION_ID_VALUE = DEFAULT_SUBSCRIPTION_ID - 1;
 
     /** @hide */
     public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
 
     /**
-     * The ICC ID of a SIM.
+     * TelephonyProvider unique key column name is the subscription id.
+     * <P>Type: TEXT (String)</P>
+     */
+    /** @hide */
+    public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
+
+    /**
+     * TelephonyProvider column name for SIM ICC Identifier
      * <P>Type: TEXT (String)</P>
      */
     /** @hide */
     public static final String ICC_ID = "icc_id";
 
     /**
+     * TelephonyProvider column name for user SIM_SlOT_INDEX
      * <P>Type: INTEGER (int)</P>
      */
     /** @hide */
-    public static final String SIM_ID = "sim_id";
+    public static final String SIM_SLOT_INDEX = "sim_id";
 
     /** SIM is not inserted */
     /** @hide */
@@ -230,39 +249,107 @@ public class SubscriptionManager implements BaseColumns {
     /**
      * Broadcast Action: The user has changed one of the default subs related to
      * data, phone calls, or sms</p>
+     *
+     * TODO: Change to a listener
      * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String SUB_DEFAULT_CHANGED_ACTION =
         "android.intent.action.SUB_DEFAULT_CHANGED";
 
+    private final Context mContext;
+
+    /**
+     * A listener class for monitoring changes to {@link SubscriptionInfo} records.
+     * <p>
+     * Override the onSubscriptionsChanged method in the object that extends this
+     * class and pass it to {@link #registerOnSubscriptionsChangedListener(OnSubscriptionsChangedListener)}
+     * to register your listener and to unregister invoke
+     * {@link #unregisterOnSubscriptionsChangedListener(OnSubscriptionsChangedListener)}
+     * <p>
+     * Permissions android.Manifest.permission.READ_PHONE_STATE is required
+     * for #onSubscriptionsChanged to be invoked.
+     */
+    public static class OnSubscriptionsChangedListener {
+        /** @hide */
+        public static final String PERMISSION_ON_SUBSCRIPTIONS_CHANGED =
+                android.Manifest.permission.READ_PHONE_STATE;
+
+        private final Handler mHandler  = new Handler() {
+            @Override
+            public void handleMessage(Message msg) {
+                if (DBG) {
+                    log("handleMessage: invoke the overriden onSubscriptionsChanged()");
+                }
+                OnSubscriptionsChangedListener.this.onSubscriptionsChanged();
+            }
+        };
+
+        /**
+         * Callback invoked when there is any change to any SubscriptionInfo. Typically
+         * this method would invoke {@link #getActiveSubscriptionInfoList}
+         */
+        public void onSubscriptionsChanged() {
+            if (DBG) log("onSubscriptionsChanged: NOT OVERRIDDEN");
+        }
+
+        /**
+         * 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.
+         */
+        IOnSubscriptionsChangedListener callback = new IOnSubscriptionsChangedListener.Stub() {
+            @Override
+            public void onSubscriptionsChanged() {
+                if (DBG) log("callbad: received, sendEmptyMessage(0) to handler");
+                mHandler.sendEmptyMessage(0);
+            }
+        };
+
+        private void log(String s) {
+            Rlog.d(LOG_TAG, s);
+        }
+    }
+
     /** @hide */
-    public SubscriptionManager() {
+    public SubscriptionManager(Context context) {
         if (DBG) logd("SubscriptionManager created");
+        mContext = context;
     }
 
     /**
-     * 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.
+     * Get an instance of the SubscriptionManager from the Context.
+     * This invokes {@link android.content.Context#getSystemService
+     * Context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)}.
      *
-     * @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
+     * @param context to use.
+     * @return SubscriptionManager instance
      */
-    public static void register(Context context, SubscriptionListener listener, int events) {
-        String pkgForDebug = context != null ? context.getPackageName() : "<unknown>";
+    public static SubscriptionManager from(Context context) {
+        return (SubscriptionManager) context.getSystemService(
+                Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+    }
+
+    /**
+     * Register for changes to the list of active {@link SubscriptionInfo} records or to the
+     * individual records themselves. When a change occurs the onSubscriptionsChanged method of
+     * the listener will be invoked immediately if there has been a notification.
+     *
+     * @param listener an instance of {@link OnSubscriptionsChangedListener} with
+     *                 onSubscriptionsChanged overridden.
+     */
+    public void registerOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
+        String pkgForDebug = mContext != null ? mContext.getPackageName() : "<unknown>";
         if (DBG) {
-            logd("SubscriptionManager listen pkgForDebug=" + pkgForDebug
-                    + " events=0x" + Integer.toHexString(events) + " listener=" + listener);
+            logd("register OnSubscriptionsChangedListener 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
+            // We use the TelephonyRegistry as it 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);
+                tr.registerOnSubscriptionsChangedListener(pkgForDebug, listener.callback);
             }
         } catch (RemoteException ex) {
             // Should not happen
@@ -270,15 +357,16 @@ public class SubscriptionManager implements BaseColumns {
     }
 
     /**
-     * Unregister the listener.
+     * Unregister the {@link OnSubscriptionsChangedListener}. This is not strictly necessary
+     * as the listener will automatically be unregistered if an attempt to invoke the listener
+     * fails.
      *
-     * @param context
-     * @param listener
+     * @param listener that is to be unregistered.
      */
-    public static void unregister(Context context, SubscriptionListener listener) {
-        String pkgForDebug = context != null ? context.getPackageName() : "<unknown>";
+    public void unregisterOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
+        String pkgForDebug = mContext != null ? mContext.getPackageName() : "<unknown>";
         if (DBG) {
-            logd("SubscriptionManager unregister pkgForDebug=" + pkgForDebug
+            logd("unregister OnSubscriptionsChangedListener pkgForDebug=" + pkgForDebug
                     + " listener=" + listener);
         }
         try {
@@ -287,7 +375,7 @@ public class SubscriptionManager implements BaseColumns {
             ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
                     "telephony.registry"));
             if (tr != null) {
-                tr.unregisterSubscriptionListener(pkgForDebug, listener.callback);
+                tr.unregisterOnSubscriptionsChangedListener(pkgForDebug, listener.callback);
             }
         } catch (RemoteException ex) {
             // Should not happen
@@ -295,13 +383,14 @@ public class SubscriptionManager implements BaseColumns {
     }
 
     /**
-     * Get the SubscriptionInfo associated with the subId
-     * @param subId The unique SubscriptionInfo index in database
-     * @return SubscriptionInfo, maybe null
+     * Get the active SubscriptionInfo with the subId key
+     * @param subId The unique SubscriptionInfo key in database
+     * @return SubscriptionInfo, maybe null if its not active.
      */
-    public static SubscriptionInfo getSubscriptionInfoForSubscriber(int subId) {
+    public SubscriptionInfo getActiveSubscriptionInfo(int subId) {
+        if (VDBG) logd("[getActiveSubscriptionInfo]+ subId=" + subId);
         if (!isValidSubId(subId)) {
-            logd("[getSubscriptionInfoForSubscriber]- invalid subId");
+            logd("[getActiveSubscriptionInfo]- invalid subId");
             return null;
         }
 
@@ -310,7 +399,7 @@ public class SubscriptionManager implements BaseColumns {
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                subInfo = iSub.getSubInfoForSubscriber(subId);
+                subInfo = iSub.getActiveSubscriptionInfo(subId);
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -321,73 +410,64 @@ public class SubscriptionManager implements BaseColumns {
     }
 
     /**
-     * Get the SubscriptionInfo according to an IccId
+     * Get the active SubscriptionInfo associated with the iccId
      * @param iccId the IccId of SIM card
-     * @return SubscriptionInfo List, maybe empty but not null
+     * @return SubscriptionInfo, maybe null if its not active
      * @hide
      */
-    public static List<SubscriptionInfo> getSubscriptionInfoUsingIccId(String iccId) {
-        if (VDBG) logd("[getSubscriptionInfoUsingIccId]+ iccId=" + iccId);
+    public SubscriptionInfo getActiveSubscriptionInfoForIccIndex(String iccId) {
+        if (VDBG) logd("[getActiveSubscriptionInfoForIccIndex]+ iccId=" + iccId);
         if (iccId == null) {
-            logd("[getSubscriptionInfoUsingIccId]- null iccid");
+            logd("[getActiveSubscriptionInfoForIccIndex]- null iccid");
             return null;
         }
 
-        List<SubscriptionInfo> result = null;
+        SubscriptionInfo result = null;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                result = iSub.getSubInfoUsingIccId(iccId);
+                result = iSub.getActiveSubscriptionInfoForIccId(iccId);
             }
         } catch (RemoteException ex) {
             // ignore it
         }
 
-
-        if (result == null) {
-            result = new ArrayList<SubscriptionInfo>();
-        }
         return result;
     }
 
     /**
-     * Get the SubscriptionInfo according to slotId
-     * @param slotId the slot which the SIM is inserted
-     * @return SubscriptionInfo list, maybe empty but not null
+     * Get the active SubscriptionInfo associated with the slotIdx
+     * @param slotIdx the slot which the subscription is inserted
+     * @return SubscriptionInfo, maybe null if its not active
      */
-    public static List<SubscriptionInfo> getSubscriptionInfoUsingSlotId(int slotId) {
-        // FIXME: Consider never returning null
-        if (!isValidSlotId(slotId)) {
-            logd("[getSubscriptionInfoUsingSlotId]- invalid slotId");
+    public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIdx) {
+        if (VDBG) logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIdx=" + slotIdx);
+        if (!isValidSlotId(slotIdx)) {
+            logd("[getActiveSubscriptionInfoForSimSlotIndex]- invalid slotIdx");
             return null;
         }
 
-        List<SubscriptionInfo> result = null;
+        SubscriptionInfo result = null;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                result = iSub.getSubInfoUsingSlotId(slotId);
+                result = iSub.getActiveSubscriptionInfoForSimSlotIndex(slotIdx);
             }
         } catch (RemoteException ex) {
             // ignore it
         }
 
-
-        if (result == null) {
-            result = new ArrayList<SubscriptionInfo>();
-        }
         return result;
     }
 
     /**
-     * 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.
+     * @return List of all SubscriptionInfo records in database,
+     * include those that were inserted before, maybe empty but not null.
      * @hide
      */
-    public static List<SubscriptionInfo> getAllSubscriptionInfoList() {
+    public List<SubscriptionInfo> getAllSubscriptionInfoList() {
         if (VDBG) logd("[getAllSubscriptionInfoList]+");
 
         List<SubscriptionInfo> result = null;
@@ -408,33 +488,45 @@ public class SubscriptionManager implements BaseColumns {
     }
 
     /**
-     * Get the SubscriptionInfo(s) of the currently inserted SIM(s)
-     * @return Array list of currently inserted SubscriptionInfo(s) maybe empty but not null
+     * Get the SubscriptionInfo(s) of the currently inserted SIM(s). The records will be sorted
+     * by {@link SubscriptionInfo#getSimSlotIndex} then by {@link SubscriptionInfo#getSubscriptionId}.
+     *
+     * @return Sorted list of the currently {@link SubscriptionInfo} records available on the device.
+     * <ul>
+     * <li>
+     * If null is returned the current state is unknown but if a {@link OnSubscriptionsChangedListener}
+     * has been registered {@link OnSubscriptionsChangedListener#onSubscriptionsChanged} will be
+     * invoked in the future.
+     * </li>
+     * <li>
+     * If the list is empty then there are no {@link SubscriptionInfo} records currently available.
+     * </li>
+     * <li>
+     * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex}
+     * then by {@link SubscriptionInfo#getSubscriptionId}.
+     * </li>
+     * </ul>
      */
-    public static List<SubscriptionInfo> getActiveSubscriptionInfoList() {
+    public List<SubscriptionInfo> getActiveSubscriptionInfoList() {
         List<SubscriptionInfo> result = null;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                result = iSub.getActiveSubInfoList();
+                result = iSub.getActiveSubscriptionInfoList();
             }
         } catch (RemoteException ex) {
             // ignore it
         }
-
-        if (result == null) {
-            result = new ArrayList<SubscriptionInfo>();
-        }
         return result;
     }
 
     /**
-     * Get the SUB count of all SUB(s) in subinfo database
-     * @return all SIM count in database, include what was inserted before
+     * @return the count of all subscriptions in the database, this includes
+     * all subscriptions that have been seen.
      * @hide
      */
-    public static int getAllSubscriptionInfoCount() {
+    public int getAllSubscriptionInfoCount() {
         if (VDBG) logd("[getAllSubscriptionInfoCount]+");
 
         int result = 0;
@@ -452,11 +544,10 @@ public class SubscriptionManager implements BaseColumns {
     }
 
     /**
-     * Get the count of active SUB(s)
-     * @return active SIM count
+     * @return the number of active subscriptions
      * @hide
      */
-    public static int getActiveSubscriptionInfoCount() {
+    public int getActiveSubscriptionInfoCount() {
         int result = 0;
 
         try {
@@ -472,13 +563,32 @@ public class SubscriptionManager implements BaseColumns {
     }
 
     /**
+     * @return the maximum number of subscriptions this device will support at any one time.
+     * @hide
+     */
+    public int getActiveSubscriptionInfoCountMax() {
+        int result = 0;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.getActiveSubInfoCountMax();
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+    }
+
+    /**
      * 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 addSubscriptionInfoRecord(String iccId, int slotId) {
+    public Uri addSubscriptionInfoRecord(String iccId, int slotId) {
         if (VDBG) logd("[addSubscriptionInfoRecord]+ iccId:" + iccId + " slotId:" + slotId);
         if (iccId == null) {
             logd("[addSubscriptionInfoRecord]- null iccId");
@@ -509,7 +619,7 @@ public class SubscriptionManager implements BaseColumns {
      * @return the number of records updated
      * @hide
      */
-    public static int setIconTint(int tint, int subId) {
+    public int setIconTint(int tint, int subId) {
         if (VDBG) logd("[setIconTint]+ tint:" + tint + " subId:" + subId);
         if (!isValidSubId(subId)) {
             logd("[setIconTint]- fail");
@@ -538,7 +648,7 @@ public class SubscriptionManager implements BaseColumns {
      * @return the number of records updated
      * @hide
      */
-    public static int setDisplayName(String displayName, int subId) {
+    public int setDisplayName(String displayName, int subId) {
         return setDisplayName(displayName, subId, NAME_SOURCE_UNDEFINDED);
     }
 
@@ -551,7 +661,7 @@ public class SubscriptionManager implements BaseColumns {
      * @return the number of records updated or -1 if invalid subId
      * @hide
      */
-    public static int setDisplayName(String displayName, int subId, long nameSource) {
+    public int setDisplayName(String displayName, int subId, long nameSource) {
         if (VDBG) {
             logd("[setDisplayName]+  displayName:" + displayName + " subId:" + subId
                     + " nameSource:" + nameSource);
@@ -583,7 +693,7 @@ public class SubscriptionManager implements BaseColumns {
      * @return the number of records updated
      * @hide
      */
-    public static int setDisplayNumber(String number, int subId) {
+    public int setDisplayNumber(String number, int subId) {
         if (number == null || !isValidSubId(subId)) {
             logd("[setDisplayNumber]- fail");
             return -1;
@@ -611,7 +721,7 @@ public class SubscriptionManager implements BaseColumns {
      * @return the number of records updated
      * @hide
      */
-    public static int setDataRoaming(int roaming, int subId) {
+    public int setDataRoaming(int roaming, int subId) {
         if (VDBG) logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId);
         if (roaming < 0 || !isValidSubId(subId)) {
             logd("[setDataRoaming]- fail");
@@ -643,7 +753,7 @@ public class SubscriptionManager implements BaseColumns {
             logd("[getSlotId]- fail");
         }
 
-        int result = INVALID_SLOT_ID;
+        int result = INVALID_SIM_SLOT_INDEX;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -683,10 +793,10 @@ public class SubscriptionManager implements BaseColumns {
     public static int getPhoneId(int subId) {
         if (!isValidSubId(subId)) {
             logd("[getPhoneId]- fail");
-            return INVALID_PHONE_ID;
+            return INVALID_PHONE_INDEX;
         }
 
-        int result = INVALID_PHONE_ID;
+        int result = INVALID_PHONE_INDEX;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -703,7 +813,7 @@ public class SubscriptionManager implements BaseColumns {
     }
 
     private static void logd(String msg) {
-        Rlog.d(LOG_TAG, "[SubManager] " + msg);
+        Rlog.d(LOG_TAG, msg);
     }
 
     /**
@@ -713,7 +823,7 @@ public class SubscriptionManager implements BaseColumns {
      * @hide
      */
     public static int getDefaultSubId() {
-        int subId = INVALID_SUB_ID;
+        int subId = INVALID_SUBSCRIPTION_ID;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -730,7 +840,7 @@ public class SubscriptionManager implements BaseColumns {
 
     /** @hide */
     public static int getDefaultVoiceSubId() {
-        int subId = INVALID_SUB_ID;
+        int subId = INVALID_SUBSCRIPTION_ID;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -746,7 +856,7 @@ public class SubscriptionManager implements BaseColumns {
     }
 
     /** @hide */
-    public static void setDefaultVoiceSubId(int subId) {
+    public void setDefaultVoiceSubId(int subId) {
         if (VDBG) logd("setDefaultVoiceSubId sub id = " + subId);
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -759,8 +869,8 @@ public class SubscriptionManager implements BaseColumns {
     }
 
     /** @hide */
-    public static SubscriptionInfo getDefaultVoiceSubscriptionInfo() {
-        return getSubscriptionInfoForSubscriber(getDefaultVoiceSubId());
+    public SubscriptionInfo getDefaultVoiceSubscriptionInfo() {
+        return getActiveSubscriptionInfo(getDefaultVoiceSubId());
     }
 
     /** @hide */
@@ -769,11 +879,13 @@ public class SubscriptionManager implements BaseColumns {
     }
 
     /**
-     * @return subId of the DefaultSms subscription or the value INVALID_SUB_ID if an error.
+     * @return subId of the DefaultSms subscription or
+     * the value INVALID_SUBSCRIPTION_ID if an error.
+     *
      * @hide
      */
     public static int getDefaultSmsSubId() {
-        int subId = INVALID_SUB_ID;
+        int subId = INVALID_SUBSCRIPTION_ID;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -789,7 +901,7 @@ public class SubscriptionManager implements BaseColumns {
     }
 
     /** @hide */
-    public static void setDefaultSmsSubId(int subId) {
+    public void setDefaultSmsSubId(int subId) {
         if (VDBG) logd("setDefaultSmsSubId sub id = " + subId);
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -802,18 +914,18 @@ public class SubscriptionManager implements BaseColumns {
     }
 
     /** @hide */
-    public static SubscriptionInfo getDefaultSmsSubscriptionInfo() {
-        return getSubscriptionInfoForSubscriber(getDefaultSmsSubId());
+    public SubscriptionInfo getDefaultSmsSubscriptionInfo() {
+        return getActiveSubscriptionInfo(getDefaultSmsSubId());
     }
 
     /** @hide */
-    public static int getDefaultSmsPhoneId() {
+    public int getDefaultSmsPhoneId() {
         return getPhoneId(getDefaultSmsSubId());
     }
 
     /** @hide */
     public static int getDefaultDataSubId() {
-        int subId = INVALID_SUB_ID;
+        int subId = INVALID_SUBSCRIPTION_ID;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -829,7 +941,7 @@ public class SubscriptionManager implements BaseColumns {
     }
 
     /** @hide */
-    public static void setDefaultDataSubId(int subId) {
+    public void setDefaultDataSubId(int subId) {
         if (VDBG) logd("setDataSubscription sub id = " + subId);
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -842,17 +954,17 @@ public class SubscriptionManager implements BaseColumns {
     }
 
     /** @hide */
-    public static SubscriptionInfo getDefaultDataSubscriptionInfo() {
-        return getSubscriptionInfoForSubscriber(getDefaultDataSubId());
+    public SubscriptionInfo getDefaultDataSubscriptionInfo() {
+        return getActiveSubscriptionInfo(getDefaultDataSubId());
     }
 
     /** @hide */
-    public static int getDefaultDataPhoneId() {
+    public int getDefaultDataPhoneId() {
         return getPhoneId(getDefaultDataSubId());
     }
 
     /** @hide */
-    public static void clearSubscriptionInfo() {
+    public void clearSubscriptionInfo() {
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
@@ -867,14 +979,14 @@ public class SubscriptionManager implements BaseColumns {
 
     //FIXME this is vulnerable to race conditions
     /** @hide */
-    public static boolean allDefaultsSelected() {
-        if (getDefaultDataSubId() == INVALID_SUB_ID) {
+    public boolean allDefaultsSelected() {
+        if (getDefaultDataSubId() == INVALID_SUBSCRIPTION_ID) {
             return false;
         }
-        if (getDefaultSmsSubId() == INVALID_SUB_ID) {
+        if (getDefaultSmsSubId() == INVALID_SUBSCRIPTION_ID) {
             return false;
         }
-        if (getDefaultVoiceSubId() == INVALID_SUB_ID) {
+        if (getDefaultVoiceSubId() == INVALID_SUBSCRIPTION_ID) {
             return false;
         }
         return true;
@@ -882,10 +994,10 @@ public class SubscriptionManager implements BaseColumns {
 
     /**
      * If a default is set to subscription which is not active, this will reset that default back to
-     * INVALID_SUB_ID.
+     * INVALID_SUBSCRIPTION_ID.
      * @hide
      */
-    public static void clearDefaultsForInactiveSubIds() {
+    public void clearDefaultsForInactiveSubIds() {
         if (VDBG) logd("clearDefaultsForInactiveSubIds");
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -902,34 +1014,26 @@ public class SubscriptionManager implements BaseColumns {
      * @hide
      */
     public static boolean isValidSubId(int subId) {
-        return subId > INVALID_SUB_ID ;
+        return subId > INVALID_SUBSCRIPTION_ID ;
     }
 
     /**
      * @return true if subId is an usable subId value else false. A
-     * usable subId means its neither a INVALID_SUB_ID nor a DEFAUL_SUB_ID.
+     * usable subId means its neither a INVALID_SUBSCRIPTION_ID nor a DEFAUL_SUB_ID.
      * @hide
      */
     public static boolean isUsableSubIdValue(int subId) {
-        return subId >= MIN_SUB_ID_VALUE && subId <= MAX_SUB_ID_VALUE;
+        return subId >= MIN_SUBSCRIPTION_ID_VALUE && subId <= MAX_SUBSCRIPTION_ID_VALUE;
     }
 
     /** @hide */
     public static boolean isValidSlotId(int slotId) {
-        // We are testing INVALID_SLOT_ID and slotId >= 0 independently because we should
-        // not assume that INVALID_SLOT_ID will always be a negative value.  Any negative
-        // value is invalid.
-        return slotId != INVALID_SLOT_ID && slotId >= 0 &&
-                slotId < TelephonyManager.getDefault().getSimCount();
+        return slotId >= 0 && slotId < TelephonyManager.getDefault().getSimCount();
     }
 
     /** @hide */
     public static boolean isValidPhoneId(int phoneId) {
-        // We are testing INVALID_PHONE_ID and phoneId >= 0 independently because we should
-        // not assume that INVALID_PHONE_ID will always be a negative value.  Any negative
-        // value is invalid.
-        return phoneId != INVALID_PHONE_ID && phoneId >= 0 &&
-                phoneId < TelephonyManager.getDefault().getPhoneCount();
+        return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount();
     }
 
     /** @hide */
@@ -957,7 +1061,7 @@ public class SubscriptionManager implements BaseColumns {
      *         is never null but the length maybe 0.
      * @hide
      */
-    public static int[] getActiveSubIdList() {
+    public int[] getActiveSubscriptionIdList() {
         int[] subId = null;
 
         try {
@@ -974,7 +1078,6 @@ public class SubscriptionManager implements BaseColumns {
         }
 
         return subId;
-
     }
 }
 
index f2d859f..f4ada87 100644 (file)
@@ -79,6 +79,7 @@ public class TelephonyManager {
     }
 
     private final Context mContext;
+    private SubscriptionManager mSubscriptionManager;
 
     private static String multiSimConfig =
             SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG);
@@ -104,6 +105,7 @@ public class TelephonyManager {
         } else {
             mContext = context;
         }
+        mSubscriptionManager = SubscriptionManager.from(mContext);
 
         if (sRegistry == null) {
             sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
@@ -157,6 +159,9 @@ public class TelephonyManager {
     public int getPhoneCount() {
         int phoneCount = 1;
         switch (getMultiSimConfiguration()) {
+            case UNKNOWN:
+                phoneCount = 1;
+                break;
             case DSDS:
             case DSDA:
                 phoneCount = PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM;
@@ -1527,7 +1532,7 @@ public class TelephonyManager {
      * @see #getSimState
      */
     public String getSimOperator() {
-        int subId = SubscriptionManager.getDefaultDataSubId();
+        int subId = mSubscriptionManager.getDefaultDataSubId();
         if (!SubscriptionManager.isUsableSubIdValue(subId)) {
             subId = SubscriptionManager.getDefaultSmsSubId();
             if (!SubscriptionManager.isUsableSubIdValue(subId)) {
@@ -1993,7 +1998,7 @@ public class TelephonyManager {
      *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
      * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
      *
-     * @param subId The subscriber id.
+     * @param subId The subscription id.
      * @param alphaTag The alpha tag to display.
      * @param number The voicemail number.
      */
diff --git a/telephony/java/com/android/internal/telephony/IOnSubscriptionsChangedListener.aidl b/telephony/java/com/android/internal/telephony/IOnSubscriptionsChangedListener.aidl
new file mode 100644 (file)
index 0000000..493b1ff
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+oneway interface IOnSubscriptionsChangedListener {
+    void onSubscriptionsChanged();
+}
+
index d82c492..ca82083 100755 (executable)
@@ -22,51 +22,71 @@ import com.android.internal.telephony.ISubscriptionListener;
 
 interface ISub {
     /**
-     * Get the SubscriptionInfo according to an index
-     * @param subId The unique SubscriptionInfo index in database
-     * @return SubscriptionInfo, maybe null
+     * @return a list of all subscriptions in the database, this includes
+     * all subscriptions that have been seen.
      */
-    SubscriptionInfo getSubInfoForSubscriber(int subId);
+    List<SubscriptionInfo> getAllSubInfoList();
 
     /**
-     * Get the SubscriptionInfo according to an IccId
-     * @param iccId the IccId of SIM card
-     * @return SubscriptionInfo, maybe null
+     * @return the count of all subscriptions in the database, this includes
+     * all subscriptions that have been seen.
      */
-    List<SubscriptionInfo> getSubInfoUsingIccId(String iccId);
+    int getAllSubInfoCount();
 
     /**
-     * Get the SubscriptionInfo according to slotId
-     * @param slotId the slot which the SIM is inserted
-     * @return SubscriptionInfo, maybe null
+     * Get the active SubscriptionInfo with the subId key
+     * @param subId The unique SubscriptionInfo key in database
+     * @return SubscriptionInfo, maybe null if its not active
      */
-    List<SubscriptionInfo> getSubInfoUsingSlotId(int slotId);
+    SubscriptionInfo getActiveSubscriptionInfo(int subId);
 
     /**
-     * Get all the SubscriptionInfo(s) in subinfo database
-     * @return Array list of all SubInfoRecords in database, include thsoe that were inserted before
+     * Get the active SubscriptionInfo associated with the iccId
+     * @param iccId the IccId of SIM card
+     * @return SubscriptionInfo, maybe null if its not active
      */
-    List<SubscriptionInfo> getAllSubInfoList();
+    SubscriptionInfo getActiveSubscriptionInfoForIccId(String iccId);
 
     /**
-     * Get the SubscriptionInfo(s) of the currently inserted SIM(s)
-     * @return Array list of currently inserted SubscriptionInfo(s)
+     * Get the active SubscriptionInfo associated with the slotIdx
+     * @param slotIdx the slot which the subscription is inserted
+     * @return SubscriptionInfo, maybe null if its not active
      */
-    List<SubscriptionInfo> getActiveSubInfoList();
+    SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIdx);
 
     /**
-     * Get the SUB count of all SUB(s) in subinfo database
-     * @return all SIM count in database, include what was inserted before
+     * Get the SubscriptionInfo(s) of the active subscriptions. The records will be sorted
+     * by {@link SubscriptionInfo#getSimSlotIndex} then by {@link SubscriptionInfo#getSubscriptionId}.
+     *
+     * @return Sorted list of the currently {@link SubscriptionInfo} records available on the device.
+     * <ul>
+     * <li>
+     * If null is returned the current state is unknown but if a {@link OnSubscriptionsChangedListener}
+     * has been registered {@link OnSubscriptionsChangedListener#onSubscriptionsChanged} will be
+     * invoked in the future.
+     * </li>
+     * <li>
+     * If the list is empty then there are no {@link SubscriptionInfo} records currently available.
+     * </li>
+     * <li>
+     * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex}
+     * then by {@link SubscriptionInfo#getSubscriptionId}.
+     * </li>
+     * </ul>
      */
-    int getAllSubInfoCount();
+    List<SubscriptionInfo> getActiveSubscriptionInfoList();
 
     /**
-     * Get the count of active SUB(s)
-     * @return active SIM count
+     * @return the number of active subscriptions
      */
     int getActiveSubInfoCount();
 
     /**
+     * @return the maximum number of subscriptions this device will support at any one time.
+     */
+    int getActiveSubInfoCountMax();
+
+    /**
      * 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
index 1a1f8fe..ba62f5f 100644 (file)
@@ -27,11 +27,13 @@ import android.telephony.SignalStrength;
 import android.telephony.CellInfo;
 import android.telephony.VoLteServiceState;
 import com.android.internal.telephony.IPhoneStateListener;
-import com.android.internal.telephony.ISubscriptionListener;
+import com.android.internal.telephony.IOnSubscriptionsChangedListener;
 
 interface ITelephonyRegistry {
-    void registerSubscriptionListener(String pkg, ISubscriptionListener callback, int events);
-    void unregisterSubscriptionListener(String pkg, ISubscriptionListener callback);
+    void registerOnSubscriptionsChangedListener(String pkg,
+            IOnSubscriptionsChangedListener callback);
+    void unregisterOnSubscriptionsChangedListener(String pkg,
+            IOnSubscriptionsChangedListener callback);
     void listen(String pkg, IPhoneStateListener callback, int events, boolean notifyNow);
     void listenForSubscriber(in int subId, String pkg, IPhoneStateListener callback, int events,
             boolean notifyNow);