Merge kwd to master

Add initial IMS and MSIM support from klp-wireless-dev-mirror

Change-Id: Idb607c0aa32f80fe4fe1539aedea7a221e9e7f04
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index cfaf016..9d92421 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -33,10 +33,13 @@
 import android.os.UserHandle;
 import android.telephony.CellLocation;
 import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.TelephonyManager;
+import android.telephony.SubscriptionManager;
 import android.telephony.PhoneStateListener;
 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;
@@ -65,8 +68,9 @@
  */
 class TelephonyRegistry extends ITelephonyRegistry.Stub {
     private static final String TAG = "TelephonyRegistry";
-    private static final boolean DBG = false;
-    private static final boolean DBG_LOC = false;
+    private static final boolean DBG = false; // STOPSHIP if true
+    private static final boolean DBG_LOC = false; // STOPSHIP if true
+    private static final boolean VDBG = false; // STOPSHIP if true
 
     private static class Record {
         String pkgForDebug;
@@ -79,6 +83,10 @@
 
         int events;
 
+        long subId;
+
+        boolean isLegacyApp;
+
         @Override
         public String toString() {
             return "{pkgForDebug=" + pkgForDebug + " callerUid=" + callerUid +
@@ -94,41 +102,47 @@
 
     private final IBatteryStats mBatteryStats;
 
-    private int mCallState = TelephonyManager.CALL_STATE_IDLE;
+    private int mNumPhones;
 
-    private String mCallIncomingNumber = "";
+    private int[] mCallState;
 
-    private ServiceState mServiceState = new ServiceState();
+    private String[] mCallIncomingNumber;
 
-    private SignalStrength mSignalStrength = new SignalStrength();
+    private ServiceState[] mServiceState;
 
-    private boolean mMessageWaiting = false;
+    private SignalStrength[] mSignalStrength;
 
-    private boolean mCallForwarding = false;
+    private boolean[] mMessageWaiting;
 
-    private int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
+    private boolean[] mCallForwarding;
 
-    private int mDataConnectionState = TelephonyManager.DATA_UNKNOWN;
+    private int[] mDataActivity;
 
-    private boolean mDataConnectionPossible = false;
+    private int[] mDataConnectionState;
 
-    private String mDataConnectionReason = "";
+    private boolean[] mDataConnectionPossible;
 
-    private String mDataConnectionApn = "";
+    private String[] mDataConnectionReason;
+
+    private String[] mDataConnectionApn;
 
     private ArrayList<String> mConnectedApns;
 
-    private LinkProperties mDataConnectionLinkProperties;
+    private LinkProperties[] mDataConnectionLinkProperties;
 
-    private NetworkCapabilities mDataConnectionNetworkCapabilities;
+    private NetworkCapabilities[] mDataConnectionNetworkCapabilities;
 
-    private Bundle mCellLocation = new Bundle();
+    private Bundle[] mCellLocation;
 
-    private int mDataConnectionNetworkType;
+    private int[] mDataConnectionNetworkType;
 
     private int mOtaspMode = ServiceStateTracker.OTASP_UNKNOWN;
 
-    private List<CellInfo> mCellInfo = null;
+    private ArrayList<List<CellInfo>> mCellInfo = null;
+
+    private VoLteServiceState mVoLteServiceState = new VoLteServiceState();
+
+    private long mDefaultSubId;
 
     private DataConnectionRealTimeInfo mDcRtInfo = new DataConnectionRealTimeInfo();
 
@@ -148,21 +162,40 @@
                 PhoneStateListener.LISTEN_CALL_STATE |
                 PhoneStateListener.LISTEN_DATA_ACTIVITY |
                 PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
-                PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR;
+                PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR |
+                PhoneStateListener.LISTEN_VOLTE_STATE;;
 
     static final int PRECISE_PHONE_STATE_PERMISSION_MASK =
                 PhoneStateListener.LISTEN_PRECISE_CALL_STATE |
                 PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE;
 
     private static final int MSG_USER_SWITCHED = 1;
+    private static final int MSG_UPDATE_DEFAULT_SUB = 2;
 
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_USER_SWITCHED: {
-                    if (DBG) Slog.d(TAG, "MSG_USER_SWITCHED userId=" + msg.arg1);
-                    TelephonyRegistry.this.notifyCellLocation(mCellLocation);
+                    Slog.d(TAG, "MSG_USER_SWITCHED userId=" + msg.arg1);
+                    int numPhones = TelephonyManager.getDefault().getPhoneCount();
+                    for (int sub = 0; sub < numPhones; sub++) {
+                        TelephonyRegistry.this.notifyCellLocationUsingSubId(sub, mCellLocation[sub]);
+                    }
+                    break;
+                }
+                case MSG_UPDATE_DEFAULT_SUB: {
+                    Slog.d(TAG, "MSG_UPDATE_DEFAULT_SUB subid=" + mDefaultSubId);
+                    // Default subscription id changed, update the changed default subscription
+                    // id in  all the legacy application listener records.
+                    synchronized (mRecords) {
+                        for (Record r : mRecords) {
+                            // FIXME: Be sure we're using isLegacyApp correctly!
+                            if (r.isLegacyApp == true) {
+                                r.subId = mDefaultSubId;
+                            }
+                        }
+                    }
                     break;
                 }
             }
@@ -173,9 +206,14 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
+            Slog.d(TAG, "mBroadcastReceiver: action=" + action);
             if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                 mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED,
                        intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
+            } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED)) {
+                mDefaultSubId = intent.getLongExtra(PhoneConstants.SUBSCRIPTION_KEY,
+                        SubscriptionManager.getDefaultSubId());
+                mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_DEFAULT_SUB, 0, 0));
             }
         }
     };
@@ -190,13 +228,55 @@
     TelephonyRegistry(Context context) {
         CellLocation  location = CellLocation.getEmpty();
 
+        mContext = context;
+        mBatteryStats = BatteryStatsService.getService();
+        mConnectedApns = new ArrayList<String>();
+
+        // Initialize default subscription to be used for single standby.
+        mDefaultSubId = SubscriptionManager.getDefaultSubId();
+
+        int numPhones = TelephonyManager.getDefault().getPhoneCount();
+        if (DBG) Slog.d(TAG, "TelephonyRegistor: ctor numPhones=" + numPhones);
+        mNumPhones = numPhones;
+        mCallState = new int[numPhones];
+        mDataActivity = new int[numPhones];
+        mDataConnectionState = new int[numPhones];
+        mDataConnectionNetworkType = new int[numPhones];
+        mCallIncomingNumber = new String[numPhones];
+        mServiceState = new ServiceState[numPhones];
+        mSignalStrength = new SignalStrength[numPhones];
+        mMessageWaiting = new boolean[numPhones];
+        mDataConnectionPossible = new boolean[numPhones];
+        mDataConnectionReason = new String[numPhones];
+        mDataConnectionApn = new String[numPhones];
+        mCallForwarding = new boolean[numPhones];
+        mCellLocation = new Bundle[numPhones];
+        mDataConnectionLinkProperties = new LinkProperties[numPhones];
+        mDataConnectionNetworkCapabilities = new NetworkCapabilities[numPhones];
+        mCellInfo = new ArrayList<List<CellInfo>>();
+        for (int i = 0; i < numPhones; i++) {
+            mCallState[i] =  TelephonyManager.CALL_STATE_IDLE;
+            mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
+            mDataConnectionState[i] = TelephonyManager.DATA_UNKNOWN;
+            mCallIncomingNumber[i] =  "";
+            mServiceState[i] =  new ServiceState();
+            mSignalStrength[i] =  new SignalStrength();
+            mMessageWaiting[i] =  false;
+            mCallForwarding[i] =  false;
+            mDataConnectionPossible[i] = false;
+            mDataConnectionReason[i] =  "";
+            mDataConnectionApn[i] =  "";
+            mCellLocation[i] = new Bundle();
+            mCellInfo.add(i, null);
+        }
+
         // Note that location can be null for non-phone builds like
         // like the generic one.
         if (location != null) {
-            location.fillInNotifierBundle(mCellLocation);
+            for (int i = 0; i < numPhones; i++) {
+                location.fillInNotifierBundle(mCellLocation[i]);
+            }
         }
-        mContext = context;
-        mBatteryStats = BatteryStatsService.getService();
         mConnectedApns = new ArrayList<String>();
     }
 
@@ -205,16 +285,31 @@
         final IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(Intent.ACTION_USER_REMOVED);
+        filter.addAction(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED);
+        Slog.d(TAG, "systemRunning register for intents");
         mContext.registerReceiver(mBroadcastReceiver, filter);
     }
 
     @Override
     public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
             boolean notifyNow) {
+        listen(pkgForDebug, callback, events, notifyNow, mDefaultSubId, true);
+    }
+
+    @Override
+    public void listenUsingSubId(long subId, String pkgForDebug, IPhoneStateListener callback,
+            int events, boolean notifyNow) {
+        listen(pkgForDebug, callback, events, notifyNow, subId, false);
+    }
+
+    private void listen(String pkgForDebug, IPhoneStateListener callback, int events,
+            boolean notifyNow, long subId, boolean isLegacyApp) {
         int callerUid = UserHandle.getCallingUserId();
         int myUid = UserHandle.myUserId();
-        if (DBG) {
+        if (VDBG) {
             Slog.d(TAG, "listen: E pkg=" + pkgForDebug + " events=0x" + Integer.toHexString(events)
+                + " notifyNow=" + notifyNow + " subId=" + subId
+                + " isLegacyApp=" + isLegacyApp
                 + " myUid=" + myUid
                 + " callerUid=" + callerUid);
         }
@@ -239,22 +334,37 @@
                     r.callback = callback;
                     r.pkgForDebug = pkgForDebug;
                     r.callerUid = callerUid;
+                    r.subId = subId;
+                    r.isLegacyApp = isLegacyApp;
+                    // Legacy applications pass invalid subId(-1), based on
+                    // the received subId value update the isLegacyApp field
+                    if ((r.subId <= 0) || (r.subId == SubscriptionManager.INVALID_SUB_ID)) {
+                        r.subId = mDefaultSubId;
+                        r.isLegacyApp = true; // FIXME: is this needed ??
+                    }
+                    if (r.subId == SubscriptionManager.DEFAULT_SUB_ID) {
+                        r.subId = mDefaultSubId;
+                        if (DBG) Slog.i(TAG, "listen: DEFAULT_SUB_ID");
+                    }
                     mRecords.add(r);
                     if (DBG) Slog.i(TAG, "listen: add new record=" + r);
                 }
+                int phoneId = SubscriptionManager.getPhoneId(subId);
                 int send = events & (events ^ r.events);
                 r.events = events;
-                if (notifyNow) {
+                if (notifyNow && validatePhoneId(phoneId)) {
                     if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
                         try {
-                            r.callback.onServiceStateChanged(new ServiceState(mServiceState));
+                            r.callback.onServiceStateChanged(
+                                    new ServiceState(mServiceState[phoneId]));
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
                         try {
-                            int gsmSignalStrength = mSignalStrength.getGsmSignalStrength();
+                            int gsmSignalStrength = mSignalStrength[phoneId]
+                                    .getGsmSignalStrength();
                             r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
                                     : gsmSignalStrength));
                         } catch (RemoteException ex) {
@@ -263,51 +373,56 @@
                     }
                     if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
                         try {
-                            r.callback.onMessageWaitingIndicatorChanged(mMessageWaiting);
+                            r.callback.onMessageWaitingIndicatorChanged(
+                                    mMessageWaiting[phoneId]);
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
                         try {
-                            r.callback.onCallForwardingIndicatorChanged(mCallForwarding);
+                            r.callback.onCallForwardingIndicatorChanged(
+                                    mCallForwarding[phoneId]);
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
                         try {
-                            if (DBG_LOC) Slog.d(TAG, "listen: mCellLocation=" + mCellLocation);
-                            r.callback.onCellLocationChanged(new Bundle(mCellLocation));
+                            if (DBG_LOC) Slog.d(TAG, "listen: mCellLocation = "
+                                    + mCellLocation[phoneId]);
+                            r.callback.onCellLocationChanged(
+                                    new Bundle(mCellLocation[phoneId]));
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if ((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
                         try {
-                            r.callback.onCallStateChanged(mCallState, mCallIncomingNumber);
+                            r.callback.onCallStateChanged(mCallState[phoneId],
+                                     mCallIncomingNumber[phoneId]);
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
                         try {
-                            r.callback.onDataConnectionStateChanged(mDataConnectionState,
-                                mDataConnectionNetworkType);
+                            r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
+                                mDataConnectionNetworkType[phoneId]);
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if ((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
                         try {
-                            r.callback.onDataActivity(mDataActivity);
+                            r.callback.onDataActivity(mDataActivity[phoneId]);
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
                     }
                     if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
                         try {
-                            r.callback.onSignalStrengthsChanged(mSignalStrength);
+                            r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
@@ -321,8 +436,9 @@
                     }
                     if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
                         try {
-                            if (DBG_LOC) Slog.d(TAG, "listen: mCellInfo=" + mCellInfo);
-                            r.callback.onCellInfoChanged(mCellInfo);
+                            if (DBG_LOC) Slog.d(TAG, "listen: mCellInfo[" + phoneId + "] = "
+                                    + mCellInfo.get(phoneId));
+                            r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
@@ -373,10 +489,10 @@
             return;
         }
         synchronized (mRecords) {
-            mCallState = state;
-            mCallIncomingNumber = incomingNumber;
             for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
+                if (((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) &&
+                    (r.isLegacyApp == true)) {
+                    // FIXME: why does isLegacyApp need to be true?
                     try {
                         r.callback.onCallStateChanged(state, incomingNumber);
                     } catch (RemoteException ex) {
@@ -386,82 +502,148 @@
             }
             handleRemoveListLocked();
         }
-        broadcastCallStateChanged(state, incomingNumber);
+        broadcastCallStateChanged(state, incomingNumber, mDefaultSubId);
     }
 
-    public void notifyServiceState(ServiceState state) {
+    public void notifyCallStateUsingSubId(long subId, int state, String incomingNumber) {
+        if (!checkNotifyPermission("notifyCallState()")) {
+            return;
+        }
+        if (VDBG) {
+            Slog.d(TAG, "notifyCallStateUsingSubId: subId=" + subId
+                + " state=" + state + " incomingNumber=" + incomingNumber);
+        }
+        synchronized (mRecords) {
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mCallState[phoneId] = state;
+                mCallIncomingNumber[phoneId] = incomingNumber;
+                for (Record r : mRecords) {
+                    if (((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) &&
+                        (r.subId == subId) && (r.isLegacyApp == false)) {
+                        // FIXME: why isLegacyApp false?
+                        try {
+                            r.callback.onCallStateChanged(state, incomingNumber);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+        broadcastCallStateChanged(state, incomingNumber, subId);
+    }
+
+     public void notifyServiceState(ServiceState state) {
+         notifyServiceStateUsingSubId(mDefaultSubId, state);
+     }
+
+    public void notifyServiceStateUsingSubId(long subId, ServiceState state) {
         if (!checkNotifyPermission("notifyServiceState()")){
             return;
         }
-        long ident = Binder.clearCallingIdentity();
-        try {
-            mBatteryStats.notePhoneState(state.getState());
-        } catch (RemoteException re) {
-            // Can't do much
-        } finally {
-            Binder.restoreCallingIdentity(ident);
+        if (subId == SubscriptionManager.DEFAULT_SUB_ID) {
+            subId = mDefaultSubId;
+            Slog.d(TAG, "notifyServiceStateUsingSubId: using mDefaultSubId=" + mDefaultSubId);
+        }
+        if (VDBG) {
+            Slog.d(TAG, "notifyServiceStateUsingSubId: subId=" + subId
+                + " state=" + state);
         }
         synchronized (mRecords) {
-            mServiceState = state;
-            for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
-                    try {
-                        r.callback.onServiceStateChanged(new ServiceState(state));
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mServiceState[phoneId] = state;
+                for (Record r : mRecords) {
+                    // FIXME: use DEFAULT_SUB_ID instead??
+                    if (((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) &&
+                            (r.subId == subId)) {
+                        try {
+                            r.callback.onServiceStateChanged(new ServiceState(state));
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
                     }
                 }
+            } else {
+                Slog.d(TAG, "notifyServiceStateUsingSubId: INVALID phoneId=" + phoneId);
             }
             handleRemoveListLocked();
         }
-        broadcastServiceStateChanged(state);
+        broadcastServiceStateChanged(state, subId);
     }
 
     public void notifySignalStrength(SignalStrength signalStrength) {
+        notifySignalStrengthUsingSubId(mDefaultSubId, signalStrength);
+    }
+
+    public void notifySignalStrengthUsingSubId(long subId, SignalStrength signalStrength) {
         if (!checkNotifyPermission("notifySignalStrength()")) {
             return;
         }
+        if (VDBG) {
+            Slog.d(TAG, "notifySignalStrengthUsingSubId: subId=" + subId
+                + " signalStrength=" + signalStrength);
+        }
         synchronized (mRecords) {
-            mSignalStrength = signalStrength;
-            for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
-                    try {
-                        r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mSignalStrength[phoneId] = signalStrength;
+                for (Record r : mRecords) {
+                    if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) &&
+                        (r.subId == subId)){
+                        try {
+                            r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
                     }
-                }
-                if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
-                    try {
-                        int gsmSignalStrength = signalStrength.getGsmSignalStrength();
-                        r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
-                                : gsmSignalStrength));
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
+                    if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) &&
+                        (r.subId == subId)) {
+                        try {
+                            int gsmSignalStrength = signalStrength.getGsmSignalStrength();
+                            r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
+                                    : gsmSignalStrength));
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
                     }
                 }
             }
             handleRemoveListLocked();
         }
-        broadcastSignalStrengthChanged(signalStrength);
+        broadcastSignalStrengthChanged(signalStrength, subId);
     }
 
     public void notifyCellInfo(List<CellInfo> cellInfo) {
+         notifyCellInfoUsingSubId(mDefaultSubId, cellInfo);
+    }
+
+    public void notifyCellInfoUsingSubId(long subId, List<CellInfo> cellInfo) {
         if (!checkNotifyPermission("notifyCellInfo()")) {
             return;
         }
+        if (VDBG) {
+            Slog.d(TAG, "notifyCellInfoUsingSubId: subId=" + subId
+                + " cellInfo=" + cellInfo);
+        }
 
         synchronized (mRecords) {
-            mCellInfo = cellInfo;
-            for (Record r : mRecords) {
-                if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
-                    try {
-                        if (DBG_LOC) {
-                            Slog.d(TAG, "notifyCellInfo: mCellInfo=" + mCellInfo + " r=" + r);
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mCellInfo.set(phoneId, cellInfo);
+                for (Record r : mRecords) {
+                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)
+                            && r.subId == subId) {
+                        try {
+                            if (DBG_LOC) {
+                                Slog.d(TAG, "notifyCellInfo: mCellInfo=" + cellInfo + " r=" + r);
+                            }
+                            r.callback.onCellInfoChanged(cellInfo);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
                         }
-                        r.callback.onCellInfoChanged(cellInfo);
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
                     }
                 }
             }
@@ -495,17 +677,29 @@
     }
 
     public void notifyMessageWaitingChanged(boolean mwi) {
+        notifyMessageWaitingChangedUsingSubId(mDefaultSubId, mwi);
+    }
+
+    public void notifyMessageWaitingChangedUsingSubId(long subId, boolean mwi) {
         if (!checkNotifyPermission("notifyMessageWaitingChanged()")) {
             return;
         }
+        if (VDBG) {
+            Slog.d(TAG, "notifyMessageWaitingChangedUsingSubId: subId=" + subId
+                + " mwi=" + mwi);
+        }
         synchronized (mRecords) {
-            mMessageWaiting = mwi;
-            for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
-                    try {
-                        r.callback.onMessageWaitingIndicatorChanged(mwi);
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mMessageWaiting[phoneId] = mwi;
+                for (Record r : mRecords) {
+                    if (((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) &&
+                        (r.subId == subId)) {
+                        try {
+                            r.callback.onMessageWaitingIndicatorChanged(mwi);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
                     }
                 }
             }
@@ -514,17 +708,29 @@
     }
 
     public void notifyCallForwardingChanged(boolean cfi) {
+        notifyCallForwardingChangedUsingSubId(mDefaultSubId, cfi);
+    }
+
+    public void notifyCallForwardingChangedUsingSubId(long subId, boolean cfi) {
         if (!checkNotifyPermission("notifyCallForwardingChanged()")) {
             return;
         }
+        if (VDBG) {
+            Slog.d(TAG, "notifyCallForwardingChangedUsingSubId: subId=" + subId
+                + " cfi=" + cfi);
+        }
         synchronized (mRecords) {
-            mCallForwarding = cfi;
-            for (Record r : mRecords) {
-                if ((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
-                    try {
-                        r.callback.onCallForwardingIndicatorChanged(cfi);
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mCallForwarding[phoneId] = cfi;
+                for (Record r : mRecords) {
+                    if (((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) &&
+                        (r.subId == subId)) {
+                        try {
+                            r.callback.onCallForwardingIndicatorChanged(cfi);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
                     }
                 }
             }
@@ -533,11 +739,16 @@
     }
 
     public void notifyDataActivity(int state) {
+        notifyDataActivityUsingSubId(mDefaultSubId, state);
+    }
+
+    public void notifyDataActivityUsingSubId(long subId, int state) {
         if (!checkNotifyPermission("notifyDataActivity()" )) {
             return;
         }
         synchronized (mRecords) {
-            mDataActivity = state;
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            mDataActivity[phoneId] = state;
             for (Record r : mRecords) {
                 if ((r.events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
                     try {
@@ -554,29 +765,40 @@
     public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
             String reason, String apn, String apnType, LinkProperties linkProperties,
             NetworkCapabilities networkCapabilities, int networkType, boolean roaming) {
+        notifyDataConnectionUsingSubId(mDefaultSubId, state, isDataConnectivityPossible,
+            reason, apn, apnType, linkProperties,
+            networkCapabilities, networkType, roaming);
+    }
+
+    public void notifyDataConnectionUsingSubId(long subId, int state,
+            boolean isDataConnectivityPossible, String reason, String apn, String apnType,
+            LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
+            int networkType, boolean roaming) {
         if (!checkNotifyPermission("notifyDataConnection()" )) {
             return;
         }
-        if (DBG) {
-            Slog.i(TAG, "notifyDataConnection: state=" + state + " isDataConnectivityPossible="
-                + isDataConnectivityPossible + " reason='" + reason
+        if (VDBG) {
+            Slog.i(TAG, "notifyDataConnectionUsingSubId: subId=" + subId
+                + " state=" + state + " isDataConnectivityPossible=" + isDataConnectivityPossible
+                + " reason='" + reason
                 + "' apn='" + apn + "' apnType=" + apnType + " networkType=" + networkType
                 + " mRecords.size()=" + mRecords.size() + " mRecords=" + mRecords);
         }
         synchronized (mRecords) {
+            int phoneId = SubscriptionManager.getPhoneId(subId);
             boolean modified = false;
             if (state == TelephonyManager.DATA_CONNECTED) {
                 if (!mConnectedApns.contains(apnType)) {
                     mConnectedApns.add(apnType);
-                    if (mDataConnectionState != state) {
-                        mDataConnectionState = state;
+                    if (mDataConnectionState[phoneId] != state) {
+                        mDataConnectionState[phoneId] = state;
                         modified = true;
                     }
                 }
             } else {
                 if (mConnectedApns.remove(apnType)) {
                     if (mConnectedApns.isEmpty()) {
-                        mDataConnectionState = state;
+                        mDataConnectionState[phoneId] = state;
                         modified = true;
                     } else {
                         // leave mDataConnectionState as is and
@@ -584,25 +806,28 @@
                     }
                 }
             }
-            mDataConnectionPossible = isDataConnectivityPossible;
-            mDataConnectionReason = reason;
-            mDataConnectionLinkProperties = linkProperties;
-            mDataConnectionNetworkCapabilities = networkCapabilities;
-            if (mDataConnectionNetworkType != networkType) {
-                mDataConnectionNetworkType = networkType;
+            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) {
-                    Slog.d(TAG, "onDataConnectionStateChanged(" + mDataConnectionState
-                        + ", " + mDataConnectionNetworkType + ")");
+                    Slog.d(TAG, "onDataConnectionStateChanged(" + mDataConnectionState[phoneId]
+                        + ", " + mDataConnectionNetworkType[phoneId] + ")");
                 }
                 for (Record r : mRecords) {
-                    if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
+                    if (((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) &&
+                            (r.subId == subId)) {
                         try {
-                            r.callback.onDataConnectionStateChanged(mDataConnectionState,
-                                    mDataConnectionNetworkType);
+                            Slog.d(TAG,"Notify data connection state changed on sub: " +
+                                    subId);
+                            r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
+                                    mDataConnectionNetworkType[phoneId]);
                         } catch (RemoteException ex) {
                             mRemoveList.add(r.binder);
                         }
@@ -624,15 +849,24 @@
             handleRemoveListLocked();
         }
         broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
-                apnType, linkProperties, networkCapabilities, roaming);
+                apnType, linkProperties, networkCapabilities, roaming, subId);
         broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn, reason,
                 linkProperties, "");
     }
 
     public void notifyDataConnectionFailed(String reason, String apnType) {
+         notifyDataConnectionFailedUsingSubId(mDefaultSubId, reason, apnType);
+    }
+
+    public void notifyDataConnectionFailedUsingSubId(long subId,
+            String reason, String apnType) {
         if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
             return;
         }
+        if (VDBG) {
+            Slog.d(TAG, "notifyDataConnectionFailedUsingSubId: subId=" + subId
+                + " reason=" + reason + " apnType=" + apnType);
+        }
         synchronized (mRecords) {
             mPreciseDataConnectionState = new PreciseDataConnectionState(
                     TelephonyManager.DATA_UNKNOWN,TelephonyManager.NETWORK_TYPE_UNKNOWN,
@@ -648,29 +882,42 @@
             }
             handleRemoveListLocked();
         }
-        broadcastDataConnectionFailed(reason, apnType);
+        broadcastDataConnectionFailed(reason, apnType, subId);
         broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
                 TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, "", reason, null, "");
     }
 
     public void notifyCellLocation(Bundle cellLocation) {
+         notifyCellLocationUsingSubId(mDefaultSubId, cellLocation);
+    }
+
+    public void notifyCellLocationUsingSubId(long subId, Bundle cellLocation) {
+        Slog.d(TAG, "notifyCellLocationUsingSubId: subId=" + subId
+                + " cellLocation=" + cellLocation);
         if (!checkNotifyPermission("notifyCellLocation()")) {
             return;
         }
+        if (VDBG) {
+            Slog.d(TAG, "notifyCellLocationUsingSubId: subId=" + subId
+                + " cellLocation=" + cellLocation);
+        }
         synchronized (mRecords) {
-            mCellLocation = cellLocation;
-            for (Record r : mRecords) {
-                if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
-                    try {
-                        if (DBG_LOC) {
-                            Slog.d(TAG, "notifyCellLocation: mCellLocation=" + mCellLocation
-                                    + " r=" + r);
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mCellLocation[phoneId] = cellLocation;
+                for (Record r : mRecords) {
+                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)
+                            && r.subId == subId) {
+                        try {
+                            if (DBG_LOC) {
+                                Slog.d(TAG, "notifyCellLocation: cellLocation=" + cellLocation
+                                        + " r=" + r);
+                            }
+                            r.callback.onCellLocationChanged(new Bundle(cellLocation));
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
                         }
-                        r.callback.onCellLocationChanged(new Bundle(cellLocation));
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
                     }
-
                 }
             }
             handleRemoveListLocked();
@@ -771,6 +1018,26 @@
                 TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, apn, reason, null, failCause);
     }
 
+    public void notifyVoLteServiceStateChanged(VoLteServiceState lteState) {
+        if (!checkNotifyPermission("notifyVoLteServiceStateChanged()")) {
+            return;
+        }
+        synchronized (mRecords) {
+            mVoLteServiceState = lteState;
+            for (Record r : mRecords) {
+                if ((r.events & PhoneStateListener.LISTEN_VOLTE_STATE) != 0) {
+                    try {
+                        r.callback.onVoLteServiceStateChanged(
+                                new VoLteServiceState(mVoLteServiceState));
+                    } catch (RemoteException ex) {
+                        mRemoveList.add(r.binder);
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -810,15 +1077,26 @@
     // the legacy intent broadcasting
     //
 
-    private void broadcastServiceStateChanged(ServiceState state) {
+    private void broadcastServiceStateChanged(ServiceState state, long subId) {
+        long ident = Binder.clearCallingIdentity();
+        try {
+            mBatteryStats.notePhoneState(state.getState());
+        } catch (RemoteException re) {
+            // Can't do much
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+
         Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
         Bundle data = new Bundle();
         state.fillInNotifierBundle(data);
         intent.putExtras(data);
+        // Pass the subscription along with the intent.
+        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
-    private void broadcastSignalStrengthChanged(SignalStrength signalStrength) {
+    private void broadcastSignalStrengthChanged(SignalStrength signalStrength, long subId) {
         long ident = Binder.clearCallingIdentity();
         try {
             mBatteryStats.notePhoneSignalStrength(signalStrength);
@@ -833,10 +1111,11 @@
         Bundle data = new Bundle();
         signalStrength.fillInNotifierBundle(data);
         intent.putExtras(data);
+        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
-    private void broadcastCallStateChanged(int state, String incomingNumber) {
+    private void broadcastCallStateChanged(int state, String incomingNumber, long subId) {
         long ident = Binder.clearCallingIdentity();
         try {
             if (state == TelephonyManager.CALL_STATE_IDLE) {
@@ -856,6 +1135,7 @@
         if (!TextUtils.isEmpty(incomingNumber)) {
             intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
         }
+        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
                 android.Manifest.permission.READ_PHONE_STATE);
     }
@@ -863,7 +1143,7 @@
     private void broadcastDataConnectionStateChanged(int state,
             boolean isDataConnectivityPossible,
             String reason, String apn, String apnType, LinkProperties linkProperties,
-            NetworkCapabilities networkCapabilities, boolean roaming) {
+            NetworkCapabilities networkCapabilities, boolean roaming, long subId) {
         // Note: not reporting to the battery stats service here, because the
         // status bar takes care of that after taking into account all of the
         // required info.
@@ -890,13 +1170,16 @@
 
         intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
         intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
+        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
-    private void broadcastDataConnectionFailed(String reason, String apnType) {
+    private void broadcastDataConnectionFailed(String reason, String apnType,
+            long subId) {
         Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
         intent.putExtra(PhoneConstants.FAILURE_REASON_KEY, reason);
         intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
+        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
@@ -989,4 +1272,10 @@
         }
         return valid;
     }
+
+    private boolean validatePhoneId(int phoneId) {
+        boolean valid = (phoneId >= 0) && (phoneId < mNumPhones);
+        if (VDBG) Slog.d(TAG, "validatePhoneId: " + valid);
+        return valid;
+    }
 }