Handle MSIM behavior for VM notifications and CFI.
Implement correct behavior for voicemail notifications, also known
as message waiting indicator (MWI) and call forwarding (CFI).
- Don't instantiate CallNotifier with a Phone object.
+ Change updateMwi and updateCfi to take the subscription id as a
parameter so the notification can be shown on a per-SIM basis.
+ Change phone state listener to be subscription-specific.
+ Register/unregister phone state listeners on subscription changes.
+ Update Cfi according to subscription-specific changes.
+ Use subscription ids as a tag on the voicemail/call forwarding
notifications so they can be shown/canceled with greater precision.
Tested:
+ Voicemail ringtone on Sprout for different SIMs.
+ Voicemail vibration on Sprout for different SIMs.
+ Call forwarding notifications on Sprout for different SIMs.
+ Remove/place SIM on Shamu to see notifications disappear/reappear.
TBD:
+ Voicemail notifications just dial the voicemail schema right now.
Need to ascertain whether we can dial a specific number, and what
happens if the number is the same for different SIMs.
Bug: 18232725
Change-Id: Ie15c3d640e8da217fa8778b2d9d904d76bf0c586
diff --git a/src/com/android/phone/CallNotifier.java b/src/com/android/phone/CallNotifier.java
index 01a2449..6f9c9dd 100644
--- a/src/com/android/phone/CallNotifier.java
+++ b/src/com/android/phone/CallNotifier.java
@@ -49,10 +49,18 @@
import android.telephony.DisconnectCause;
import android.telephony.PhoneNumberUtils;
import android.telephony.PhoneStateListener;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
import android.util.EventLog;
import android.util.Log;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
/**
* Phone app module that listens for phone state changes and various other
* events from the telephony layer, and triggers any resulting UI behavior
@@ -85,6 +93,8 @@
// object used to synchronize access to mCallerInfoQueryState
private Object mCallerInfoQueryStateGuard = new Object();
+ private Map<Integer, CallNotifierPhoneStateListener> mPhoneStateListeners =
+ new ArrayMap<Integer, CallNotifierPhoneStateListener>();
private PhoneGlobals mApplication;
private CallManager mCM;
@@ -103,20 +113,22 @@
// Cached AudioManager
private AudioManager mAudioManager;
-
private final BluetoothManager mBluetoothManager;
+ private SubscriptionManager mSubscriptionManager;
+ private TelephonyManager mTelephonyManager;
/**
* Initialize the singleton CallNotifier instance.
* This is only done once, at startup, from PhoneApp.onCreate().
*/
- /* package */ static CallNotifier init(PhoneGlobals app, Phone phone,
- CallLogger callLogger, CallStateMonitor callStateMonitor,
+ /* package */ static CallNotifier init(
+ PhoneGlobals app,
+ CallLogger callLogger,
+ CallStateMonitor callStateMonitor,
BluetoothManager bluetoothManager) {
synchronized (CallNotifier.class) {
if (sInstance == null) {
- sInstance = new CallNotifier(app, phone, callLogger, callStateMonitor,
- bluetoothManager);
+ sInstance = new CallNotifier(app, callLogger, callStateMonitor, bluetoothManager);
} else {
Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
}
@@ -125,29 +137,38 @@
}
/** Private constructor; @see init() */
- private CallNotifier(PhoneGlobals app, Phone phone, CallLogger callLogger,
- CallStateMonitor callStateMonitor, BluetoothManager bluetoothManager) {
+ private CallNotifier(
+ PhoneGlobals app,
+ CallLogger callLogger,
+ CallStateMonitor callStateMonitor,
+ BluetoothManager bluetoothManager) {
mApplication = app;
mCM = app.mCM;
mCallLogger = callLogger;
mBluetoothManager = bluetoothManager;
mAudioManager = (AudioManager) mApplication.getSystemService(Context.AUDIO_SERVICE);
+ mTelephonyManager =
+ (TelephonyManager) mApplication.getSystemService(Context.TELEPHONY_SERVICE);
+ mSubscriptionManager = (SubscriptionManager) mApplication.getSystemService(
+ Context.TELEPHONY_SUBSCRIPTION_SERVICE);
callStateMonitor.addListener(this);
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null) {
adapter.getProfileProxy(mApplication.getApplicationContext(),
- mBluetoothProfileServiceListener,
- BluetoothProfile.HEADSET);
+ mBluetoothProfileServiceListener,
+ BluetoothProfile.HEADSET);
}
- TelephonyManager telephonyManager = (TelephonyManager) app.getSystemService(
- Context.TELEPHONY_SERVICE);
- telephonyManager.listen(mPhoneStateListener,
- PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
- | PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR);
+ mSubscriptionManager.registerOnSubscriptionsChangedListener(
+ new OnSubscriptionsChangedListener() {
+ @Override
+ public void onSubscriptionsChanged() {
+ updatePhoneStateListeners();
+ }
+ });
}
private void createSignalInfoToneGenerator() {
@@ -239,20 +260,6 @@
}
}
- PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
- @Override
- public void onMessageWaitingIndicatorChanged(boolean visible) {
- if (VDBG) log("onMessageWaitingIndicatorChanged(): " + visible);
- mApplication.notificationMgr.updateMwi(visible);
- }
-
- @Override
- public void onCallForwardingIndicatorChanged(boolean visible) {
- if (VDBG) log("onCallForwardingIndicatorChanged(): " + visible);
- mApplication.notificationMgr.updateCfi(visible);
- }
- };
-
/**
* Handles a "new ringing connection" event from the telephony layer.
*/
@@ -913,6 +920,58 @@
SHOW_MESSAGE_NOTIFICATION_TIME);
}
+ public void updatePhoneStateListeners() {
+ List<SubscriptionInfo> subInfos = mSubscriptionManager.getActiveSubscriptionInfoList();
+
+ // Unregister phone listeners for inactive subscriptions.
+ Iterator<Integer> itr = mPhoneStateListeners.keySet().iterator();
+ while (itr.hasNext()) {
+ int subId = itr.next();
+ if (subInfos == null || !containsSubId(subInfos, subId)) {
+ // Hide the outstanding notifications.
+ mApplication.notificationMgr.updateMwi(subId, false);
+ mApplication.notificationMgr.updateCfi(subId, false);
+
+ // Listening to LISTEN_NONE removes the listener.
+ mTelephonyManager.listen(
+ mPhoneStateListeners.get(subId), PhoneStateListener.LISTEN_NONE);
+ itr.remove();
+ }
+ }
+
+ if (subInfos == null) {
+ return;
+ }
+
+ // Register new phone listeners for active subscriptions.
+ for (int i = 0; i < subInfos.size(); i++) {
+ int subId = subInfos.get(i).getSubscriptionId();
+ if (!mPhoneStateListeners.containsKey(subId)) {
+ CallNotifierPhoneStateListener listener = new CallNotifierPhoneStateListener(subId);
+ mTelephonyManager.listen(listener,
+ PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
+ | PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR);
+ mPhoneStateListeners.put(subId, listener);
+ }
+ }
+ }
+
+ /**
+ * @return {@code true} if the list contains SubscriptionInfo with the given subscription id.
+ */
+ private boolean containsSubId(List<SubscriptionInfo> subInfos, int subId) {
+ if (subInfos == null) {
+ return false;
+ }
+
+ for (int i = 0; i < subInfos.size(); i++) {
+ if (subInfos.get(i).getSubscriptionId() == subId) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Helper class to play SignalInfo tones using the ToneGenerator.
*
@@ -1014,14 +1073,32 @@
}
private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
- new BluetoothProfile.ServiceListener() {
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- mBluetoothHeadset = (BluetoothHeadset) proxy;
- if (VDBG) log("- Got BluetoothHeadset: " + mBluetoothHeadset);
+ new BluetoothProfile.ServiceListener() {
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ mBluetoothHeadset = (BluetoothHeadset) proxy;
+ if (VDBG) log("- Got BluetoothHeadset: " + mBluetoothHeadset);
+ }
+
+ public void onServiceDisconnected(int profile) {
+ mBluetoothHeadset = null;
+ }
+ };
+
+ private class CallNotifierPhoneStateListener extends PhoneStateListener {
+ public CallNotifierPhoneStateListener(int subId) {
+ super(subId);
}
- public void onServiceDisconnected(int profile) {
- mBluetoothHeadset = null;
+ @Override
+ public void onMessageWaitingIndicatorChanged(boolean visible) {
+ if (VDBG) log("onMessageWaitingIndicatorChanged(): " + this.mSubId + " " + visible);
+ mApplication.notificationMgr.updateMwi(this.mSubId, visible);
+ }
+
+ @Override
+ public void onCallForwardingIndicatorChanged(boolean visible) {
+ if (VDBG) log("onCallForwardingIndicatorChanged(): " + this.mSubId + " " + visible);
+ mApplication.notificationMgr.updateCfi(this.mSubId, visible);
}
};