Loading src/java/com/android/internal/telephony/PhoneConfigurationManager.java +18 −14 Original line number Original line Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.os.SystemProperties; import android.os.storage.StorageManager; import android.os.storage.StorageManager; import android.telephony.PhoneCapability; import android.telephony.PhoneCapability; import android.telephony.Rlog; import android.telephony.Rlog; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager; import android.util.Log; import android.util.Log; Loading Loading @@ -129,19 +130,6 @@ public class PhoneConfigurationManager { return sInstance; return sInstance; } } /** * Whether the phoneId has a corresponding active slot / logical modem. If a DSDS capable * device is in single SIM mode, phoneId=1 is valid but not active. * * TODO: b/139642279 combine with SubscriptionManager#isValidPhoneId when phone objects * are dynamically allocated instead of always based on getMaxPhoneCount. * @hide */ public static boolean isPhoneActive(int phoneId) { // Currently it simply depends on getPhoneCount. In future it can be generalized. return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount(); } /** /** * Handler class to handle callbacks * Handler class to handle callbacks */ */ Loading Loading @@ -366,11 +354,12 @@ public class PhoneConfigurationManager { pm.reboot("Multi-SIM config changed."); pm.reboot("Multi-SIM config changed."); } else { } else { log("onMultiSimConfigChanged: Rebooting is not required."); log("onMultiSimConfigChanged: Rebooting is not required."); mMi.notifyPhoneFactoryOnMultiSimConfigChanged(mContext, numOfActiveModems); broadcastMultiSimConfigChange(numOfActiveModems); broadcastMultiSimConfigChange(numOfActiveModems); // Register to RIL service if needed. // Register to RIL service if needed. for (int i = 0; i < mPhones.length; i++) { for (int i = 0; i < mPhones.length; i++) { Phone phone = mPhones[i]; Phone phone = mPhones[i]; phone.mCi.onSlotActiveStatusChange(isPhoneActive(i)); phone.mCi.onSlotActiveStatusChange(SubscriptionManager.isValidPhoneId(i)); } } } } } } Loading Loading @@ -426,6 +415,9 @@ public class PhoneConfigurationManager { */ */ @VisibleForTesting @VisibleForTesting public static class MockableInterface { public static class MockableInterface { /** * Wrapper function to decide whether reboot is required for modem config change. */ @VisibleForTesting @VisibleForTesting public boolean isRebootRequiredForModemConfigChange() { public boolean isRebootRequiredForModemConfigChange() { String rebootRequired = SystemProperties.get( String rebootRequired = SystemProperties.get( Loading @@ -434,6 +426,9 @@ public class PhoneConfigurationManager { return !rebootRequired.equals("false"); return !rebootRequired.equals("false"); } } /** * Wrapper function to call setMultiSimProperties. */ @VisibleForTesting @VisibleForTesting public void setMultiSimProperties(int numOfActiveModems) { public void setMultiSimProperties(int numOfActiveModems) { String multiSimConfig; String multiSimConfig; Loading @@ -451,6 +446,15 @@ public class PhoneConfigurationManager { log("setMultiSimProperties to " + multiSimConfig); log("setMultiSimProperties to " + multiSimConfig); SystemProperties.set(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG, multiSimConfig); SystemProperties.set(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG, multiSimConfig); } } /** * Wrapper function to call PhoneFactory.onMultiSimConfigChanged. */ @VisibleForTesting public void notifyPhoneFactoryOnMultiSimConfigChanged( Context context, int numOfActiveModems) { PhoneFactory.onMultiSimConfigChanged(context, numOfActiveModems); } } } private static void log(String s) { private static void log(String s) { Loading src/java/com/android/internal/telephony/PhoneFactory.java +66 −21 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,11 @@ package com.android.internal.telephony; package com.android.internal.telephony; import static com.android.internal.telephony.PhoneConstants.PHONE_TYPE_CDMA; import static com.android.internal.telephony.PhoneConstants.PHONE_TYPE_CDMA_LTE; import static java.util.Arrays.copyOf; import android.annotation.Nullable; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.ComponentName; Loading Loading @@ -145,7 +150,7 @@ public class PhoneFactory { /* In case of multi SIM mode two instances of Phone, RIL are created, /* In case of multi SIM mode two instances of Phone, RIL are created, where as in single SIM mode only instance. isMultiSimEnabled() function checks where as in single SIM mode only instance. isMultiSimEnabled() function checks whether it is single SIM or multi SIM mode */ whether it is single SIM or multi SIM mode */ int numPhones = TelephonyManager.getDefault().getSupportedModemCount(); int numPhones = TelephonyManager.getDefault().getActiveModemCount(); int[] networkModes = new int[numPhones]; int[] networkModes = new int[numPhones]; sPhones = new Phone[numPhones]; sPhones = new Phone[numPhones]; Loading @@ -164,7 +169,7 @@ public class PhoneFactory { // Instantiate UiccController so that all other classes can just // Instantiate UiccController so that all other classes can just // call getInstance() // call getInstance() sUiccController = UiccController.make(context, sCommandsInterfaces); sUiccController = UiccController.make(context); Rlog.i(LOG_TAG, "Creating SubscriptionController"); Rlog.i(LOG_TAG, "Creating SubscriptionController"); SubscriptionController sc = SubscriptionController.init(context); SubscriptionController sc = SubscriptionController.init(context); Loading @@ -177,28 +182,13 @@ public class PhoneFactory { } } for (int i = 0; i < numPhones; i++) { for (int i = 0; i < numPhones; i++) { Phone phone = null; sPhones[i] = createPhone(context, i); int phoneType = TelephonyManager.getPhoneType(networkModes[i]); if (phoneType == PhoneConstants.PHONE_TYPE_GSM) { phone = new GsmCdmaPhone(context, sCommandsInterfaces[i], sPhoneNotifier, i, PhoneConstants.PHONE_TYPE_GSM, TelephonyComponentFactory.getInstance()); } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) { phone = new GsmCdmaPhone(context, sCommandsInterfaces[i], sPhoneNotifier, i, PhoneConstants.PHONE_TYPE_CDMA_LTE, TelephonyComponentFactory.getInstance()); } Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i); sPhones[i] = phone; } } // Set the default phone in base class. // Set the default phone in base class. // FIXME: This is a first best guess at what the defaults will be. It // FIXME: This is a first best guess at what the defaults will be. It // FIXME: needs to be done in a more controlled manner in the future. // FIXME: needs to be done in a more controlled manner in the future. sPhone = sPhones[0]; if (numPhones > 0) sPhone = sPhones[0]; // Ensure that we have a default SMS app. Requesting the app with // Ensure that we have a default SMS app. Requesting the app with // updateIfNeeded set to true is enough to configure a default SMS app. // updateIfNeeded set to true is enough to configure a default SMS app. Loading @@ -218,7 +208,6 @@ public class PhoneFactory { Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater "); Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater "); sSubInfoRecordUpdater = new SubscriptionInfoUpdater( sSubInfoRecordUpdater = new SubscriptionInfoUpdater( BackgroundThread.get().getLooper(), context, sCommandsInterfaces); BackgroundThread.get().getLooper(), context, sCommandsInterfaces); sc.updatePhonesAvailability(sPhones); // Only bring up IMS if the device supports having an IMS stack. // Only bring up IMS if the device supports having an IMS stack. if (context.getPackageManager().hasSystemFeature( if (context.getPackageManager().hasSystemFeature( Loading Loading @@ -260,7 +249,7 @@ public class PhoneFactory { sContext, sc, Looper.myLooper(), tr, sCommandsInterfaces, sContext, sc, Looper.myLooper(), tr, sCommandsInterfaces, sPhones); sPhones); sProxyController = ProxyController.getInstance(context, sPhones, sPhoneSwitcher); sProxyController = ProxyController.getInstance(context); sIntentBroadcaster = IntentBroadcaster.getInstance(context); sIntentBroadcaster = IntentBroadcaster.getInstance(context); Loading @@ -274,6 +263,53 @@ public class PhoneFactory { } } } } /** * Upon single SIM to dual SIM switch or vice versa, we dynamically allocate or de-allocate * Phone and CommandInterface objects. * @param context * @param activeModemCount */ public static void onMultiSimConfigChanged(Context context, int activeModemCount) { synchronized (sLockProxyPhones) { int prevActiveModemCount = sPhones.length; if (prevActiveModemCount == activeModemCount) return; // TODO: clean up sPhones, sCommandsInterfaces and sTelephonyNetworkFactories objects. // Currently we will not clean up the 2nd Phone object, so that it can be re-used if // user switches back. if (prevActiveModemCount > activeModemCount) return; sPhones = copyOf(sPhones, activeModemCount); sCommandsInterfaces = copyOf(sCommandsInterfaces, activeModemCount); sTelephonyNetworkFactories = copyOf(sTelephonyNetworkFactories, activeModemCount); int cdmaSubscription = CdmaSubscriptionSourceManager.getDefault(context); for (int i = prevActiveModemCount; i < activeModemCount; i++) { sCommandsInterfaces[i] = new RIL(context, RILConstants.PREFERRED_NETWORK_MODE, cdmaSubscription, i); sPhones[i] = createPhone(context, i); if (context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_TELEPHONY_IMS)) { sPhones[i].startMonitoringImsService(); } sTelephonyNetworkFactories[i] = new TelephonyNetworkFactory( Looper.myLooper(), sPhones[i]); } } } private static Phone createPhone(Context context, int phoneId) { int phoneType = TelephonyManager.getPhoneType(RILConstants.PREFERRED_NETWORK_MODE); Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " phoneId = " + phoneId); // We always use PHONE_TYPE_CDMA_LTE now. if (phoneType == PHONE_TYPE_CDMA) phoneType = PHONE_TYPE_CDMA_LTE; return new GsmCdmaPhone(context, sCommandsInterfaces[phoneId], sPhoneNotifier, phoneId, phoneType, TelephonyComponentFactory.getInstance()); } @UnsupportedAppUsage @UnsupportedAppUsage public static Phone getDefaultPhone() { public static Phone getDefaultPhone() { synchronized (sLockProxyPhones) { synchronized (sLockProxyPhones) { Loading Loading @@ -458,6 +494,15 @@ public class PhoneFactory { } } } } /** * Get Command Interfaces. */ public static CommandsInterface[] getCommandsInterfaces() { synchronized (sLockProxyPhones) { return sCommandsInterfaces; } } /** /** * Adds a local log category. * Adds a local log category. * * Loading src/java/com/android/internal/telephony/PhoneSubInfoController.java +3 −6 Original line number Original line Diff line number Diff line Loading @@ -42,14 +42,11 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub { private static final boolean DBG = true; private static final boolean DBG = true; private static final boolean VDBG = false; // STOPSHIP if true private static final boolean VDBG = false; // STOPSHIP if true @UnsupportedAppUsage private final Phone[] mPhone; @UnsupportedAppUsage @UnsupportedAppUsage private final Context mContext; private final Context mContext; private final AppOpsManager mAppOps; private final AppOpsManager mAppOps; public PhoneSubInfoController(Context context, Phone[] phone) { public PhoneSubInfoController(Context context) { mPhone = phone; if (ServiceManager.getService("iphonesubinfo") == null) { if (ServiceManager.getService("iphonesubinfo") == null) { ServiceManager.addService("iphonesubinfo", this); ServiceManager.addService("iphonesubinfo", this); } } Loading Loading @@ -221,7 +218,7 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub { if (!SubscriptionManager.isValidPhoneId(phoneId)) { if (!SubscriptionManager.isValidPhoneId(phoneId)) { phoneId = 0; phoneId = 0; } } return mPhone[phoneId]; return PhoneFactory.getPhone(phoneId); } } /** /** Loading Loading @@ -465,7 +462,7 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub { if (!SubscriptionManager.isValidPhoneId(phoneId)) { if (!SubscriptionManager.isValidPhoneId(phoneId)) { phoneId = 0; phoneId = 0; } } final Phone phone = mPhone[phoneId]; final Phone phone = PhoneFactory.getPhone(phoneId); if (phone == null) { if (phone == null) { return null; return null; } } Loading src/java/com/android/internal/telephony/ProxyController.java +44 −10 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.internal.telephony; package com.android.internal.telephony; import static java.util.Arrays.copyOf; import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Context; import android.content.Intent; import android.content.Intent; Loading @@ -30,6 +32,7 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager; import android.util.Log; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.ims.RcsMessageController; import com.android.internal.telephony.ims.RcsMessageController; import java.util.ArrayList; import java.util.ArrayList; Loading @@ -45,6 +48,8 @@ public class ProxyController { private static final int EVENT_APPLY_RC_RESPONSE = 3; private static final int EVENT_APPLY_RC_RESPONSE = 3; private static final int EVENT_FINISH_RC_RESPONSE = 4; private static final int EVENT_FINISH_RC_RESPONSE = 4; private static final int EVENT_TIMEOUT = 5; private static final int EVENT_TIMEOUT = 5; @VisibleForTesting public static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 6; private static final int SET_RC_STATUS_IDLE = 0; private static final int SET_RC_STATUS_IDLE = 0; private static final int SET_RC_STATUS_STARTING = 1; private static final int SET_RC_STATUS_STARTING = 1; Loading Loading @@ -105,9 +110,9 @@ public class ProxyController { //***** Class Methods //***** Class Methods public static ProxyController getInstance(Context context, Phone[] phone, PhoneSwitcher ps) { public static ProxyController getInstance(Context context) { if (sProxyController == null) { if (sProxyController == null) { sProxyController = new ProxyController(context, phone, ps); sProxyController = new ProxyController(context); } } return sProxyController; return sProxyController; } } Loading @@ -117,17 +122,17 @@ public class ProxyController { return sProxyController; return sProxyController; } } private ProxyController(Context context, Phone[] phone, PhoneSwitcher phoneSwitcher) { private ProxyController(Context context) { logd("Constructor - Enter"); logd("Constructor - Enter"); mContext = context; mContext = context; mPhones = phone; mPhones = PhoneFactory.getPhones(); mPhoneSwitcher = phoneSwitcher; mPhoneSwitcher = PhoneSwitcher.getInstance(); RcsMessageController.init(context); RcsMessageController.init(context); mUiccPhoneBookController = new UiccPhoneBookController(mPhones); mUiccPhoneBookController = new UiccPhoneBookController(); mPhoneSubInfoController = new PhoneSubInfoController(mContext, mPhones); mPhoneSubInfoController = new PhoneSubInfoController(mContext); mSmsController = new SmsController(mContext); mSmsController = new SmsController(mContext); mSetRadioAccessFamilyStatus = new int[mPhones.length]; mSetRadioAccessFamilyStatus = new int[mPhones.length]; mNewRadioAccessFamily = new int[mPhones.length]; mNewRadioAccessFamily = new int[mPhones.length]; Loading @@ -146,6 +151,9 @@ public class ProxyController { mPhones[i].registerForRadioCapabilityChanged( mPhones[i].registerForRadioCapabilityChanged( mHandler, EVENT_NOTIFICATION_RC_CHANGED, null); mHandler, EVENT_NOTIFICATION_RC_CHANGED, null); } } PhoneConfigurationManager.registerForMultiSimConfigChange( mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED, null); logd("Constructor - Exit"); logd("Constructor - Exit"); } } Loading Loading @@ -201,7 +209,7 @@ public class ProxyController { */ */ public boolean setRadioCapability(RadioAccessFamily[] rafs) { public boolean setRadioCapability(RadioAccessFamily[] rafs) { if (rafs.length != mPhones.length) { if (rafs.length != mPhones.length) { throw new RuntimeException("Length of input rafs must equal to total phone count"); return false; } } // Check if there is any ongoing transaction and throw an exception if there // Check if there is any ongoing transaction and throw an exception if there // is one as this is a programming error. // is one as this is a programming error. Loading Loading @@ -291,7 +299,8 @@ public class ProxyController { return true; return true; } } private Handler mHandler = new Handler() { @VisibleForTesting public final Handler mHandler = new Handler() { @Override @Override public void handleMessage(Message msg) { public void handleMessage(Message msg) { logd("handleMessage msg.what=" + msg.what); logd("handleMessage msg.what=" + msg.what); Loading @@ -316,12 +325,37 @@ public class ProxyController { onTimeoutRadioCapability(msg); onTimeoutRadioCapability(msg); break; break; case EVENT_MULTI_SIM_CONFIG_CHANGED: onMultiSimConfigChanged(); break; default: default: break; break; } } } } }; }; private void onMultiSimConfigChanged() { int oldPhoneCount = mPhones.length; mPhones = PhoneFactory.getPhones(); // Re-size arrays. mSetRadioAccessFamilyStatus = copyOf(mSetRadioAccessFamilyStatus, mPhones.length); mNewRadioAccessFamily = copyOf(mNewRadioAccessFamily, mPhones.length); mOldRadioAccessFamily = copyOf(mOldRadioAccessFamily, mPhones.length); mCurrentLogicalModemIds = copyOf(mCurrentLogicalModemIds, mPhones.length); mNewLogicalModemIds = copyOf(mNewLogicalModemIds, mPhones.length); // Clear to be sure we're in the initial state clearTransaction(); // Register radio cap change for new phones. for (int i = oldPhoneCount; i < mPhones.length; i++) { mPhones[i].registerForRadioCapabilityChanged( mHandler, EVENT_NOTIFICATION_RC_CHANGED, null); } } /** /** * Handle START response * Handle START response * @param msg obj field isa RadioCapability * @param msg obj field isa RadioCapability Loading src/java/com/android/internal/telephony/RIL.java +5 −2 Original line number Original line Diff line number Diff line Loading @@ -91,6 +91,7 @@ import android.telephony.Rlog; import android.telephony.ServiceState; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SignalStrength; import android.telephony.SmsManager; import android.telephony.SmsManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyHistogram; import android.telephony.TelephonyHistogram; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.PrefNetworkMode; import android.telephony.TelephonyManager.PrefNetworkMode; Loading Loading @@ -413,7 +414,7 @@ public class RIL extends BaseCommands implements CommandsInterface { /** Returns a {@link IRadio} instance or null if the service is not available. */ /** Returns a {@link IRadio} instance or null if the service is not available. */ @VisibleForTesting @VisibleForTesting public synchronized IRadio getRadioProxy(Message result) { public synchronized IRadio getRadioProxy(Message result) { if (!PhoneConfigurationManager.isPhoneActive(mPhoneId)) return null; if (!SubscriptionManager.isValidPhoneId(mPhoneId)) return null; if (!mIsMobileNetworkSupported) { if (!mIsMobileNetworkSupported) { if (RILJ_LOGV) riljLog("getRadioProxy: Not calling getService(): wifi-only"); if (RILJ_LOGV) riljLog("getRadioProxy: Not calling getService(): wifi-only"); if (result != null) { if (result != null) { Loading Loading @@ -510,13 +511,15 @@ public class RIL extends BaseCommands implements CommandsInterface { // Try to connect to RIL services and set response functions. // Try to connect to RIL services and set response functions. getRadioProxy(null); getRadioProxy(null); getOemHookProxy(null); getOemHookProxy(null); } else { resetProxyAndRequestList(); } } } } /** Returns an {@link IOemHook} instance or null if the service is not available. */ /** Returns an {@link IOemHook} instance or null if the service is not available. */ @VisibleForTesting @VisibleForTesting public synchronized IOemHook getOemHookProxy(Message result) { public synchronized IOemHook getOemHookProxy(Message result) { if (!PhoneConfigurationManager.isPhoneActive(mPhoneId)) return null; if (!SubscriptionManager.isValidPhoneId((mPhoneId))) return null; if (!mIsMobileNetworkSupported) { if (!mIsMobileNetworkSupported) { if (RILJ_LOGV) riljLog("getOemHookProxy: Not calling getService(): wifi-only"); if (RILJ_LOGV) riljLog("getOemHookProxy: Not calling getService(): wifi-only"); if (result != null) { if (result != null) { Loading Loading
src/java/com/android/internal/telephony/PhoneConfigurationManager.java +18 −14 Original line number Original line Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.os.SystemProperties; import android.os.storage.StorageManager; import android.os.storage.StorageManager; import android.telephony.PhoneCapability; import android.telephony.PhoneCapability; import android.telephony.Rlog; import android.telephony.Rlog; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager; import android.util.Log; import android.util.Log; Loading Loading @@ -129,19 +130,6 @@ public class PhoneConfigurationManager { return sInstance; return sInstance; } } /** * Whether the phoneId has a corresponding active slot / logical modem. If a DSDS capable * device is in single SIM mode, phoneId=1 is valid but not active. * * TODO: b/139642279 combine with SubscriptionManager#isValidPhoneId when phone objects * are dynamically allocated instead of always based on getMaxPhoneCount. * @hide */ public static boolean isPhoneActive(int phoneId) { // Currently it simply depends on getPhoneCount. In future it can be generalized. return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount(); } /** /** * Handler class to handle callbacks * Handler class to handle callbacks */ */ Loading Loading @@ -366,11 +354,12 @@ public class PhoneConfigurationManager { pm.reboot("Multi-SIM config changed."); pm.reboot("Multi-SIM config changed."); } else { } else { log("onMultiSimConfigChanged: Rebooting is not required."); log("onMultiSimConfigChanged: Rebooting is not required."); mMi.notifyPhoneFactoryOnMultiSimConfigChanged(mContext, numOfActiveModems); broadcastMultiSimConfigChange(numOfActiveModems); broadcastMultiSimConfigChange(numOfActiveModems); // Register to RIL service if needed. // Register to RIL service if needed. for (int i = 0; i < mPhones.length; i++) { for (int i = 0; i < mPhones.length; i++) { Phone phone = mPhones[i]; Phone phone = mPhones[i]; phone.mCi.onSlotActiveStatusChange(isPhoneActive(i)); phone.mCi.onSlotActiveStatusChange(SubscriptionManager.isValidPhoneId(i)); } } } } } } Loading Loading @@ -426,6 +415,9 @@ public class PhoneConfigurationManager { */ */ @VisibleForTesting @VisibleForTesting public static class MockableInterface { public static class MockableInterface { /** * Wrapper function to decide whether reboot is required for modem config change. */ @VisibleForTesting @VisibleForTesting public boolean isRebootRequiredForModemConfigChange() { public boolean isRebootRequiredForModemConfigChange() { String rebootRequired = SystemProperties.get( String rebootRequired = SystemProperties.get( Loading @@ -434,6 +426,9 @@ public class PhoneConfigurationManager { return !rebootRequired.equals("false"); return !rebootRequired.equals("false"); } } /** * Wrapper function to call setMultiSimProperties. */ @VisibleForTesting @VisibleForTesting public void setMultiSimProperties(int numOfActiveModems) { public void setMultiSimProperties(int numOfActiveModems) { String multiSimConfig; String multiSimConfig; Loading @@ -451,6 +446,15 @@ public class PhoneConfigurationManager { log("setMultiSimProperties to " + multiSimConfig); log("setMultiSimProperties to " + multiSimConfig); SystemProperties.set(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG, multiSimConfig); SystemProperties.set(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG, multiSimConfig); } } /** * Wrapper function to call PhoneFactory.onMultiSimConfigChanged. */ @VisibleForTesting public void notifyPhoneFactoryOnMultiSimConfigChanged( Context context, int numOfActiveModems) { PhoneFactory.onMultiSimConfigChanged(context, numOfActiveModems); } } } private static void log(String s) { private static void log(String s) { Loading
src/java/com/android/internal/telephony/PhoneFactory.java +66 −21 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,11 @@ package com.android.internal.telephony; package com.android.internal.telephony; import static com.android.internal.telephony.PhoneConstants.PHONE_TYPE_CDMA; import static com.android.internal.telephony.PhoneConstants.PHONE_TYPE_CDMA_LTE; import static java.util.Arrays.copyOf; import android.annotation.Nullable; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.ComponentName; Loading Loading @@ -145,7 +150,7 @@ public class PhoneFactory { /* In case of multi SIM mode two instances of Phone, RIL are created, /* In case of multi SIM mode two instances of Phone, RIL are created, where as in single SIM mode only instance. isMultiSimEnabled() function checks where as in single SIM mode only instance. isMultiSimEnabled() function checks whether it is single SIM or multi SIM mode */ whether it is single SIM or multi SIM mode */ int numPhones = TelephonyManager.getDefault().getSupportedModemCount(); int numPhones = TelephonyManager.getDefault().getActiveModemCount(); int[] networkModes = new int[numPhones]; int[] networkModes = new int[numPhones]; sPhones = new Phone[numPhones]; sPhones = new Phone[numPhones]; Loading @@ -164,7 +169,7 @@ public class PhoneFactory { // Instantiate UiccController so that all other classes can just // Instantiate UiccController so that all other classes can just // call getInstance() // call getInstance() sUiccController = UiccController.make(context, sCommandsInterfaces); sUiccController = UiccController.make(context); Rlog.i(LOG_TAG, "Creating SubscriptionController"); Rlog.i(LOG_TAG, "Creating SubscriptionController"); SubscriptionController sc = SubscriptionController.init(context); SubscriptionController sc = SubscriptionController.init(context); Loading @@ -177,28 +182,13 @@ public class PhoneFactory { } } for (int i = 0; i < numPhones; i++) { for (int i = 0; i < numPhones; i++) { Phone phone = null; sPhones[i] = createPhone(context, i); int phoneType = TelephonyManager.getPhoneType(networkModes[i]); if (phoneType == PhoneConstants.PHONE_TYPE_GSM) { phone = new GsmCdmaPhone(context, sCommandsInterfaces[i], sPhoneNotifier, i, PhoneConstants.PHONE_TYPE_GSM, TelephonyComponentFactory.getInstance()); } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) { phone = new GsmCdmaPhone(context, sCommandsInterfaces[i], sPhoneNotifier, i, PhoneConstants.PHONE_TYPE_CDMA_LTE, TelephonyComponentFactory.getInstance()); } Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i); sPhones[i] = phone; } } // Set the default phone in base class. // Set the default phone in base class. // FIXME: This is a first best guess at what the defaults will be. It // FIXME: This is a first best guess at what the defaults will be. It // FIXME: needs to be done in a more controlled manner in the future. // FIXME: needs to be done in a more controlled manner in the future. sPhone = sPhones[0]; if (numPhones > 0) sPhone = sPhones[0]; // Ensure that we have a default SMS app. Requesting the app with // Ensure that we have a default SMS app. Requesting the app with // updateIfNeeded set to true is enough to configure a default SMS app. // updateIfNeeded set to true is enough to configure a default SMS app. Loading @@ -218,7 +208,6 @@ public class PhoneFactory { Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater "); Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater "); sSubInfoRecordUpdater = new SubscriptionInfoUpdater( sSubInfoRecordUpdater = new SubscriptionInfoUpdater( BackgroundThread.get().getLooper(), context, sCommandsInterfaces); BackgroundThread.get().getLooper(), context, sCommandsInterfaces); sc.updatePhonesAvailability(sPhones); // Only bring up IMS if the device supports having an IMS stack. // Only bring up IMS if the device supports having an IMS stack. if (context.getPackageManager().hasSystemFeature( if (context.getPackageManager().hasSystemFeature( Loading Loading @@ -260,7 +249,7 @@ public class PhoneFactory { sContext, sc, Looper.myLooper(), tr, sCommandsInterfaces, sContext, sc, Looper.myLooper(), tr, sCommandsInterfaces, sPhones); sPhones); sProxyController = ProxyController.getInstance(context, sPhones, sPhoneSwitcher); sProxyController = ProxyController.getInstance(context); sIntentBroadcaster = IntentBroadcaster.getInstance(context); sIntentBroadcaster = IntentBroadcaster.getInstance(context); Loading @@ -274,6 +263,53 @@ public class PhoneFactory { } } } } /** * Upon single SIM to dual SIM switch or vice versa, we dynamically allocate or de-allocate * Phone and CommandInterface objects. * @param context * @param activeModemCount */ public static void onMultiSimConfigChanged(Context context, int activeModemCount) { synchronized (sLockProxyPhones) { int prevActiveModemCount = sPhones.length; if (prevActiveModemCount == activeModemCount) return; // TODO: clean up sPhones, sCommandsInterfaces and sTelephonyNetworkFactories objects. // Currently we will not clean up the 2nd Phone object, so that it can be re-used if // user switches back. if (prevActiveModemCount > activeModemCount) return; sPhones = copyOf(sPhones, activeModemCount); sCommandsInterfaces = copyOf(sCommandsInterfaces, activeModemCount); sTelephonyNetworkFactories = copyOf(sTelephonyNetworkFactories, activeModemCount); int cdmaSubscription = CdmaSubscriptionSourceManager.getDefault(context); for (int i = prevActiveModemCount; i < activeModemCount; i++) { sCommandsInterfaces[i] = new RIL(context, RILConstants.PREFERRED_NETWORK_MODE, cdmaSubscription, i); sPhones[i] = createPhone(context, i); if (context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_TELEPHONY_IMS)) { sPhones[i].startMonitoringImsService(); } sTelephonyNetworkFactories[i] = new TelephonyNetworkFactory( Looper.myLooper(), sPhones[i]); } } } private static Phone createPhone(Context context, int phoneId) { int phoneType = TelephonyManager.getPhoneType(RILConstants.PREFERRED_NETWORK_MODE); Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " phoneId = " + phoneId); // We always use PHONE_TYPE_CDMA_LTE now. if (phoneType == PHONE_TYPE_CDMA) phoneType = PHONE_TYPE_CDMA_LTE; return new GsmCdmaPhone(context, sCommandsInterfaces[phoneId], sPhoneNotifier, phoneId, phoneType, TelephonyComponentFactory.getInstance()); } @UnsupportedAppUsage @UnsupportedAppUsage public static Phone getDefaultPhone() { public static Phone getDefaultPhone() { synchronized (sLockProxyPhones) { synchronized (sLockProxyPhones) { Loading Loading @@ -458,6 +494,15 @@ public class PhoneFactory { } } } } /** * Get Command Interfaces. */ public static CommandsInterface[] getCommandsInterfaces() { synchronized (sLockProxyPhones) { return sCommandsInterfaces; } } /** /** * Adds a local log category. * Adds a local log category. * * Loading
src/java/com/android/internal/telephony/PhoneSubInfoController.java +3 −6 Original line number Original line Diff line number Diff line Loading @@ -42,14 +42,11 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub { private static final boolean DBG = true; private static final boolean DBG = true; private static final boolean VDBG = false; // STOPSHIP if true private static final boolean VDBG = false; // STOPSHIP if true @UnsupportedAppUsage private final Phone[] mPhone; @UnsupportedAppUsage @UnsupportedAppUsage private final Context mContext; private final Context mContext; private final AppOpsManager mAppOps; private final AppOpsManager mAppOps; public PhoneSubInfoController(Context context, Phone[] phone) { public PhoneSubInfoController(Context context) { mPhone = phone; if (ServiceManager.getService("iphonesubinfo") == null) { if (ServiceManager.getService("iphonesubinfo") == null) { ServiceManager.addService("iphonesubinfo", this); ServiceManager.addService("iphonesubinfo", this); } } Loading Loading @@ -221,7 +218,7 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub { if (!SubscriptionManager.isValidPhoneId(phoneId)) { if (!SubscriptionManager.isValidPhoneId(phoneId)) { phoneId = 0; phoneId = 0; } } return mPhone[phoneId]; return PhoneFactory.getPhone(phoneId); } } /** /** Loading Loading @@ -465,7 +462,7 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub { if (!SubscriptionManager.isValidPhoneId(phoneId)) { if (!SubscriptionManager.isValidPhoneId(phoneId)) { phoneId = 0; phoneId = 0; } } final Phone phone = mPhone[phoneId]; final Phone phone = PhoneFactory.getPhone(phoneId); if (phone == null) { if (phone == null) { return null; return null; } } Loading
src/java/com/android/internal/telephony/ProxyController.java +44 −10 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.internal.telephony; package com.android.internal.telephony; import static java.util.Arrays.copyOf; import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Context; import android.content.Intent; import android.content.Intent; Loading @@ -30,6 +32,7 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager; import android.util.Log; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.ims.RcsMessageController; import com.android.internal.telephony.ims.RcsMessageController; import java.util.ArrayList; import java.util.ArrayList; Loading @@ -45,6 +48,8 @@ public class ProxyController { private static final int EVENT_APPLY_RC_RESPONSE = 3; private static final int EVENT_APPLY_RC_RESPONSE = 3; private static final int EVENT_FINISH_RC_RESPONSE = 4; private static final int EVENT_FINISH_RC_RESPONSE = 4; private static final int EVENT_TIMEOUT = 5; private static final int EVENT_TIMEOUT = 5; @VisibleForTesting public static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 6; private static final int SET_RC_STATUS_IDLE = 0; private static final int SET_RC_STATUS_IDLE = 0; private static final int SET_RC_STATUS_STARTING = 1; private static final int SET_RC_STATUS_STARTING = 1; Loading Loading @@ -105,9 +110,9 @@ public class ProxyController { //***** Class Methods //***** Class Methods public static ProxyController getInstance(Context context, Phone[] phone, PhoneSwitcher ps) { public static ProxyController getInstance(Context context) { if (sProxyController == null) { if (sProxyController == null) { sProxyController = new ProxyController(context, phone, ps); sProxyController = new ProxyController(context); } } return sProxyController; return sProxyController; } } Loading @@ -117,17 +122,17 @@ public class ProxyController { return sProxyController; return sProxyController; } } private ProxyController(Context context, Phone[] phone, PhoneSwitcher phoneSwitcher) { private ProxyController(Context context) { logd("Constructor - Enter"); logd("Constructor - Enter"); mContext = context; mContext = context; mPhones = phone; mPhones = PhoneFactory.getPhones(); mPhoneSwitcher = phoneSwitcher; mPhoneSwitcher = PhoneSwitcher.getInstance(); RcsMessageController.init(context); RcsMessageController.init(context); mUiccPhoneBookController = new UiccPhoneBookController(mPhones); mUiccPhoneBookController = new UiccPhoneBookController(); mPhoneSubInfoController = new PhoneSubInfoController(mContext, mPhones); mPhoneSubInfoController = new PhoneSubInfoController(mContext); mSmsController = new SmsController(mContext); mSmsController = new SmsController(mContext); mSetRadioAccessFamilyStatus = new int[mPhones.length]; mSetRadioAccessFamilyStatus = new int[mPhones.length]; mNewRadioAccessFamily = new int[mPhones.length]; mNewRadioAccessFamily = new int[mPhones.length]; Loading @@ -146,6 +151,9 @@ public class ProxyController { mPhones[i].registerForRadioCapabilityChanged( mPhones[i].registerForRadioCapabilityChanged( mHandler, EVENT_NOTIFICATION_RC_CHANGED, null); mHandler, EVENT_NOTIFICATION_RC_CHANGED, null); } } PhoneConfigurationManager.registerForMultiSimConfigChange( mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED, null); logd("Constructor - Exit"); logd("Constructor - Exit"); } } Loading Loading @@ -201,7 +209,7 @@ public class ProxyController { */ */ public boolean setRadioCapability(RadioAccessFamily[] rafs) { public boolean setRadioCapability(RadioAccessFamily[] rafs) { if (rafs.length != mPhones.length) { if (rafs.length != mPhones.length) { throw new RuntimeException("Length of input rafs must equal to total phone count"); return false; } } // Check if there is any ongoing transaction and throw an exception if there // Check if there is any ongoing transaction and throw an exception if there // is one as this is a programming error. // is one as this is a programming error. Loading Loading @@ -291,7 +299,8 @@ public class ProxyController { return true; return true; } } private Handler mHandler = new Handler() { @VisibleForTesting public final Handler mHandler = new Handler() { @Override @Override public void handleMessage(Message msg) { public void handleMessage(Message msg) { logd("handleMessage msg.what=" + msg.what); logd("handleMessage msg.what=" + msg.what); Loading @@ -316,12 +325,37 @@ public class ProxyController { onTimeoutRadioCapability(msg); onTimeoutRadioCapability(msg); break; break; case EVENT_MULTI_SIM_CONFIG_CHANGED: onMultiSimConfigChanged(); break; default: default: break; break; } } } } }; }; private void onMultiSimConfigChanged() { int oldPhoneCount = mPhones.length; mPhones = PhoneFactory.getPhones(); // Re-size arrays. mSetRadioAccessFamilyStatus = copyOf(mSetRadioAccessFamilyStatus, mPhones.length); mNewRadioAccessFamily = copyOf(mNewRadioAccessFamily, mPhones.length); mOldRadioAccessFamily = copyOf(mOldRadioAccessFamily, mPhones.length); mCurrentLogicalModemIds = copyOf(mCurrentLogicalModemIds, mPhones.length); mNewLogicalModemIds = copyOf(mNewLogicalModemIds, mPhones.length); // Clear to be sure we're in the initial state clearTransaction(); // Register radio cap change for new phones. for (int i = oldPhoneCount; i < mPhones.length; i++) { mPhones[i].registerForRadioCapabilityChanged( mHandler, EVENT_NOTIFICATION_RC_CHANGED, null); } } /** /** * Handle START response * Handle START response * @param msg obj field isa RadioCapability * @param msg obj field isa RadioCapability Loading
src/java/com/android/internal/telephony/RIL.java +5 −2 Original line number Original line Diff line number Diff line Loading @@ -91,6 +91,7 @@ import android.telephony.Rlog; import android.telephony.ServiceState; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SignalStrength; import android.telephony.SmsManager; import android.telephony.SmsManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyHistogram; import android.telephony.TelephonyHistogram; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.PrefNetworkMode; import android.telephony.TelephonyManager.PrefNetworkMode; Loading Loading @@ -413,7 +414,7 @@ public class RIL extends BaseCommands implements CommandsInterface { /** Returns a {@link IRadio} instance or null if the service is not available. */ /** Returns a {@link IRadio} instance or null if the service is not available. */ @VisibleForTesting @VisibleForTesting public synchronized IRadio getRadioProxy(Message result) { public synchronized IRadio getRadioProxy(Message result) { if (!PhoneConfigurationManager.isPhoneActive(mPhoneId)) return null; if (!SubscriptionManager.isValidPhoneId(mPhoneId)) return null; if (!mIsMobileNetworkSupported) { if (!mIsMobileNetworkSupported) { if (RILJ_LOGV) riljLog("getRadioProxy: Not calling getService(): wifi-only"); if (RILJ_LOGV) riljLog("getRadioProxy: Not calling getService(): wifi-only"); if (result != null) { if (result != null) { Loading Loading @@ -510,13 +511,15 @@ public class RIL extends BaseCommands implements CommandsInterface { // Try to connect to RIL services and set response functions. // Try to connect to RIL services and set response functions. getRadioProxy(null); getRadioProxy(null); getOemHookProxy(null); getOemHookProxy(null); } else { resetProxyAndRequestList(); } } } } /** Returns an {@link IOemHook} instance or null if the service is not available. */ /** Returns an {@link IOemHook} instance or null if the service is not available. */ @VisibleForTesting @VisibleForTesting public synchronized IOemHook getOemHookProxy(Message result) { public synchronized IOemHook getOemHookProxy(Message result) { if (!PhoneConfigurationManager.isPhoneActive(mPhoneId)) return null; if (!SubscriptionManager.isValidPhoneId((mPhoneId))) return null; if (!mIsMobileNetworkSupported) { if (!mIsMobileNetworkSupported) { if (RILJ_LOGV) riljLog("getOemHookProxy: Not calling getService(): wifi-only"); if (RILJ_LOGV) riljLog("getOemHookProxy: Not calling getService(): wifi-only"); if (result != null) { if (result != null) { Loading