Loading src/java/com/android/internal/telephony/PhoneSwitcher.java +153 −12 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ import android.os.RemoteException; import android.telephony.CarrierConfigManager; import android.telephony.PhoneCapability; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.TelephonyRegistryManager; Loading @@ -78,7 +79,9 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; /** Loading Loading @@ -271,6 +274,7 @@ public class PhoneSwitcher extends Handler { @VisibleForTesting public static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 117; private static final int EVENT_NETWORK_AVAILABLE = 118; private static final int EVENT_PROCESS_SIM_STATE_CHANGE = 119; // Depending on version of IRadioConfig, we need to send either RIL_REQUEST_ALLOW_DATA if it's // 1.0, or RIL_REQUEST_SET_PREFERRED_DATA if it's 1.1 or later. So internally mHalCommandToUse Loading @@ -291,6 +295,8 @@ public class PhoneSwitcher extends Handler { private ConnectivityManager mConnectivityManager; private List<Set<CommandException.Error>> mCurrentDdsSwitchFailure; private class DefaultNetworkCallback extends ConnectivityManager.NetworkCallback { public int mExpectedSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; public int mSwitchReason = TelephonyEvent.DataSwitch.Reason.DATA_SWITCH_REASON_UNKNOWN; Loading Loading @@ -402,6 +408,11 @@ public class PhoneSwitcher extends Handler { mRadioConfig = RadioConfig.getInstance(); mValidator = CellularNetworkValidator.getInstance(); mCurrentDdsSwitchFailure = new ArrayList<Set<CommandException.Error>>(); IntentFilter filter = new IntentFilter(); filter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); mContext.registerReceiver(mSimStateIntentReceiver, filter); mActivePhoneRegistrants = new RegistrantList(); for (int i = 0; i < mActiveModemCount; i++) { mPhoneStates[i] = new PhoneState(); Loading @@ -418,6 +429,8 @@ public class PhoneSwitcher extends Handler { PhoneFactory.getPhone(i).getDataEnabledSettings().registerForDataEnabledChanged( this, EVENT_DATA_ENABLED_CHANGED, null); } Set<CommandException.Error> ddsFailure = new HashSet<CommandException.Error>(); mCurrentDdsSwitchFailure.add(ddsFailure); } if (mActiveModemCount > 0) { Loading Loading @@ -461,6 +474,8 @@ public class PhoneSwitcher extends Handler { // we want to see all requests networkFactory.registerIgnoringScore(); updateHalCommandToUse(); log("PhoneSwitcher started"); } Loading @@ -472,6 +487,40 @@ public class PhoneSwitcher extends Handler { } }; private BroadcastReceiver mSimStateIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED)) { int state = intent.getIntExtra(TelephonyManager.EXTRA_SIM_STATE, TelephonyManager.SIM_STATE_UNKNOWN); int slotIndex = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, SubscriptionManager.INVALID_SIM_SLOT_INDEX); log("mSimStateIntentReceiver: slotIndex = " + slotIndex + " state = " + state); obtainMessage(EVENT_PROCESS_SIM_STATE_CHANGE, slotIndex, state).sendToTarget(); } } }; private boolean isSimApplicationReady(int slotIndex) { if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { return false; } SubscriptionInfo info = SubscriptionController.getInstance() .getActiveSubscriptionInfoForSimSlotIndex(slotIndex, mContext.getOpPackageName(), null); boolean uiccAppsEnabled = info != null && info.areUiccApplicationsEnabled(); IccCard iccCard = PhoneFactory.getPhone(slotIndex).getIccCard(); if (!iccCard.isEmptyProfile() && uiccAppsEnabled) { log("isSimApplicationReady: SIM is ready for slotIndex: " + slotIndex); return true; } else { return false; } } private final SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionsChangedListener = new SubscriptionManager.OnSubscriptionsChangedListener() { @Override Loading Loading @@ -542,9 +591,21 @@ public class PhoneSwitcher extends Handler { break; } case EVENT_PRECISE_CALL_STATE_CHANGED: { log("EVENT_PRECISE_CALL_STATE_CHANGED"); // If the phoneId in voice call didn't change, do nothing. if (!isPhoneInVoiceCallChanged()) break; if (!isAnyVoiceCallActiveOnDevice()) { for (int i = 0; i < mActiveModemCount; i++) { if (mCurrentDdsSwitchFailure.get(i).contains( CommandException.Error.OP_NOT_ALLOWED_DURING_VOICE_CALL) && isPhoneIdValidForRetry(i)) { sendRilCommands(i); } } } // Only handle this event if we are currently waiting for the emergency call // associated with the override request to start or end. if (mEmergencyOverride != null && mEmergencyOverride.mPendingOriginatingCall) { Loading Loading @@ -595,18 +656,21 @@ public class PhoneSwitcher extends Handler { mEmergencyOverride.sendOverrideCompleteCallbackResultAndClear(commandSuccess); // Do not retry , as we do not allow changes in onEvaluate during an emergency // call. When the call ends, we will start the countdown to remove the override. } else if (!commandSuccess) { } else { int phoneId = (int) ar.userObj; log("Modem command failed. with exception " + ar.exception); sendMessageDelayed(Message.obtain(this, EVENT_MODEM_COMMAND_RETRY, phoneId), MODEM_COMMAND_RETRY_PERIOD_MS); onDdsSwitchResponse(ar, phoneId); } break; } case EVENT_MODEM_COMMAND_RETRY: { int phoneId = (int) msg.obj; log("Resend modem command on phone " + phoneId); if (isPhoneIdValidForRetry(phoneId)) { log("EVENT_MODEM_COMMAND_RETRY: resend modem command on phone " + phoneId); sendRilCommands(phoneId); } else { log("EVENT_MODEM_COMMAND_RETRY: skip retry as DDS sub changed"); mCurrentDdsSwitchFailure.get(phoneId).clear(); } break; } case EVENT_OVERRIDE_DDS_FOR_EMERGENCY: { Loading Loading @@ -664,6 +728,21 @@ public class PhoneSwitcher extends Handler { onMultiSimConfigChanged(activeModemCount); break; } case EVENT_PROCESS_SIM_STATE_CHANGE: { int slotIndex = (int) msg.arg1; int simState = (int) msg.arg2; if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { log("EVENT_PROCESS_SIM_STATE_CHANGE: skip processing due to invalid slotId: " + slotIndex); } else if (mCurrentDdsSwitchFailure.get(slotIndex).contains( CommandException.Error.INVALID_SIM_STATE) && (TelephonyManager.SIM_STATE_LOADED == simState) && isSimApplicationReady(slotIndex)) { sendRilCommands(slotIndex); } break; } } } Loading @@ -675,6 +754,8 @@ public class PhoneSwitcher extends Handler { mPhoneSubscriptions = copyOf(mPhoneSubscriptions, mActiveModemCount); mPhoneStates = copyOf(mPhoneStates, mActiveModemCount); //clear the list in case of multisim config change mCurrentDdsSwitchFailure.clear(); // Single SIM -> dual SIM switch. for (int phoneId = oldActiveModemCount; phoneId < mActiveModemCount; phoneId++) { Loading @@ -691,6 +772,9 @@ public class PhoneSwitcher extends Handler { } phone.getDataEnabledSettings().registerForDataEnabledChanged( this, EVENT_DATA_ENABLED_CHANGED, null); Set<CommandException.Error> ddsFailure = new HashSet<CommandException.Error>(); mCurrentDdsSwitchFailure.add(ddsFailure); } } Loading Loading @@ -947,11 +1031,6 @@ public class PhoneSwitcher extends Handler { activate(phoneId); } } notifyPreferredDataSubIdChanged(); // Notify all registrants. mActivePhoneRegistrants.notifyRegistrants(); } return diffDetected; } Loading Loading @@ -1021,7 +1100,10 @@ public class PhoneSwitcher extends Handler { } protected void sendRilCommands(int phoneId) { if (!SubscriptionManager.isValidPhoneId(phoneId)) return; if (!SubscriptionManager.isValidPhoneId(phoneId)) { log("sendRilCommands: skip dds switch due to invalid phoneid=" + phoneId); return; } Message message = Message.obtain(this, EVENT_MODEM_COMMAND_DONE, phoneId); if (mHalCommandToUse == HAL_COMMAND_ALLOW_DATA || mHalCommandToUse == HAL_COMMAND_UNKNOWN) { Loading Loading @@ -1455,4 +1537,63 @@ public class PhoneSwitcher extends Handler { mLocalLog.dump(fd, pw, args); pw.decreaseIndent(); } private boolean isAnyVoiceCallActiveOnDevice() { boolean ret = mPhoneIdInVoiceCall != SubscriptionManager.INVALID_PHONE_INDEX; log("isAnyVoiceCallActiveOnDevice: " + ret); return ret; } private void onDdsSwitchResponse(AsyncResult ar, int phoneId) { if (ar.exception != null) { log("onDdsSwitchResponse: DDS switch failed. with exception " + ar.exception); if (ar.exception instanceof CommandException) { CommandException.Error error = ((CommandException) (ar.exception)).getCommandError(); mCurrentDdsSwitchFailure.get(phoneId).add(error); if (error == CommandException.Error.OP_NOT_ALLOWED_DURING_VOICE_CALL) { log("onDdsSwitchResponse: Wait for call end indication"); return; } else if (error == CommandException.Error.INVALID_SIM_STATE) { /* If there is a attach failure due to sim not ready then hold the retry until sim gets ready */ log("onDdsSwitchResponse: Wait for SIM to get READY"); return; } } log("onDdsSwitchResponse: Scheduling DDS switch retry"); sendMessageDelayed(Message.obtain(this, EVENT_MODEM_COMMAND_RETRY, phoneId), MODEM_COMMAND_RETRY_PERIOD_MS); } else { log("onDdsSwitchResponse: DDS switch success on phoneId = " + phoneId); mCurrentDdsSwitchFailure.get(phoneId).clear(); // Notify all registrants mActivePhoneRegistrants.notifyRegistrants(); notifyPreferredDataSubIdChanged(); } } private boolean isPhoneIdValidForRetry(int phoneId) { int phoneIdForRequest = INVALID_PHONE_INDEX; int ddsPhoneId = mSubscriptionController.getPhoneId( mSubscriptionController.getDefaultDataSubId()); if (ddsPhoneId != INVALID_PHONE_INDEX && ddsPhoneId == phoneId) { return true; } else { if (mPrioritizedDcRequests.size() == 0) { return false; } for (int i = 0; i < mMaxDataAttachModemCount; i++) { DcRequest dcRequest = mPrioritizedDcRequests.get(i); if (dcRequest != null) { phoneIdForRequest = phoneIdForRequest(dcRequest.networkRequest); if (phoneIdForRequest == phoneId) { return true; } } } } return false; } } tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java +115 −5 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
src/java/com/android/internal/telephony/PhoneSwitcher.java +153 −12 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ import android.os.RemoteException; import android.telephony.CarrierConfigManager; import android.telephony.PhoneCapability; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.TelephonyRegistryManager; Loading @@ -78,7 +79,9 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; /** Loading Loading @@ -271,6 +274,7 @@ public class PhoneSwitcher extends Handler { @VisibleForTesting public static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 117; private static final int EVENT_NETWORK_AVAILABLE = 118; private static final int EVENT_PROCESS_SIM_STATE_CHANGE = 119; // Depending on version of IRadioConfig, we need to send either RIL_REQUEST_ALLOW_DATA if it's // 1.0, or RIL_REQUEST_SET_PREFERRED_DATA if it's 1.1 or later. So internally mHalCommandToUse Loading @@ -291,6 +295,8 @@ public class PhoneSwitcher extends Handler { private ConnectivityManager mConnectivityManager; private List<Set<CommandException.Error>> mCurrentDdsSwitchFailure; private class DefaultNetworkCallback extends ConnectivityManager.NetworkCallback { public int mExpectedSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; public int mSwitchReason = TelephonyEvent.DataSwitch.Reason.DATA_SWITCH_REASON_UNKNOWN; Loading Loading @@ -402,6 +408,11 @@ public class PhoneSwitcher extends Handler { mRadioConfig = RadioConfig.getInstance(); mValidator = CellularNetworkValidator.getInstance(); mCurrentDdsSwitchFailure = new ArrayList<Set<CommandException.Error>>(); IntentFilter filter = new IntentFilter(); filter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); mContext.registerReceiver(mSimStateIntentReceiver, filter); mActivePhoneRegistrants = new RegistrantList(); for (int i = 0; i < mActiveModemCount; i++) { mPhoneStates[i] = new PhoneState(); Loading @@ -418,6 +429,8 @@ public class PhoneSwitcher extends Handler { PhoneFactory.getPhone(i).getDataEnabledSettings().registerForDataEnabledChanged( this, EVENT_DATA_ENABLED_CHANGED, null); } Set<CommandException.Error> ddsFailure = new HashSet<CommandException.Error>(); mCurrentDdsSwitchFailure.add(ddsFailure); } if (mActiveModemCount > 0) { Loading Loading @@ -461,6 +474,8 @@ public class PhoneSwitcher extends Handler { // we want to see all requests networkFactory.registerIgnoringScore(); updateHalCommandToUse(); log("PhoneSwitcher started"); } Loading @@ -472,6 +487,40 @@ public class PhoneSwitcher extends Handler { } }; private BroadcastReceiver mSimStateIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED)) { int state = intent.getIntExtra(TelephonyManager.EXTRA_SIM_STATE, TelephonyManager.SIM_STATE_UNKNOWN); int slotIndex = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, SubscriptionManager.INVALID_SIM_SLOT_INDEX); log("mSimStateIntentReceiver: slotIndex = " + slotIndex + " state = " + state); obtainMessage(EVENT_PROCESS_SIM_STATE_CHANGE, slotIndex, state).sendToTarget(); } } }; private boolean isSimApplicationReady(int slotIndex) { if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { return false; } SubscriptionInfo info = SubscriptionController.getInstance() .getActiveSubscriptionInfoForSimSlotIndex(slotIndex, mContext.getOpPackageName(), null); boolean uiccAppsEnabled = info != null && info.areUiccApplicationsEnabled(); IccCard iccCard = PhoneFactory.getPhone(slotIndex).getIccCard(); if (!iccCard.isEmptyProfile() && uiccAppsEnabled) { log("isSimApplicationReady: SIM is ready for slotIndex: " + slotIndex); return true; } else { return false; } } private final SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionsChangedListener = new SubscriptionManager.OnSubscriptionsChangedListener() { @Override Loading Loading @@ -542,9 +591,21 @@ public class PhoneSwitcher extends Handler { break; } case EVENT_PRECISE_CALL_STATE_CHANGED: { log("EVENT_PRECISE_CALL_STATE_CHANGED"); // If the phoneId in voice call didn't change, do nothing. if (!isPhoneInVoiceCallChanged()) break; if (!isAnyVoiceCallActiveOnDevice()) { for (int i = 0; i < mActiveModemCount; i++) { if (mCurrentDdsSwitchFailure.get(i).contains( CommandException.Error.OP_NOT_ALLOWED_DURING_VOICE_CALL) && isPhoneIdValidForRetry(i)) { sendRilCommands(i); } } } // Only handle this event if we are currently waiting for the emergency call // associated with the override request to start or end. if (mEmergencyOverride != null && mEmergencyOverride.mPendingOriginatingCall) { Loading Loading @@ -595,18 +656,21 @@ public class PhoneSwitcher extends Handler { mEmergencyOverride.sendOverrideCompleteCallbackResultAndClear(commandSuccess); // Do not retry , as we do not allow changes in onEvaluate during an emergency // call. When the call ends, we will start the countdown to remove the override. } else if (!commandSuccess) { } else { int phoneId = (int) ar.userObj; log("Modem command failed. with exception " + ar.exception); sendMessageDelayed(Message.obtain(this, EVENT_MODEM_COMMAND_RETRY, phoneId), MODEM_COMMAND_RETRY_PERIOD_MS); onDdsSwitchResponse(ar, phoneId); } break; } case EVENT_MODEM_COMMAND_RETRY: { int phoneId = (int) msg.obj; log("Resend modem command on phone " + phoneId); if (isPhoneIdValidForRetry(phoneId)) { log("EVENT_MODEM_COMMAND_RETRY: resend modem command on phone " + phoneId); sendRilCommands(phoneId); } else { log("EVENT_MODEM_COMMAND_RETRY: skip retry as DDS sub changed"); mCurrentDdsSwitchFailure.get(phoneId).clear(); } break; } case EVENT_OVERRIDE_DDS_FOR_EMERGENCY: { Loading Loading @@ -664,6 +728,21 @@ public class PhoneSwitcher extends Handler { onMultiSimConfigChanged(activeModemCount); break; } case EVENT_PROCESS_SIM_STATE_CHANGE: { int slotIndex = (int) msg.arg1; int simState = (int) msg.arg2; if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { log("EVENT_PROCESS_SIM_STATE_CHANGE: skip processing due to invalid slotId: " + slotIndex); } else if (mCurrentDdsSwitchFailure.get(slotIndex).contains( CommandException.Error.INVALID_SIM_STATE) && (TelephonyManager.SIM_STATE_LOADED == simState) && isSimApplicationReady(slotIndex)) { sendRilCommands(slotIndex); } break; } } } Loading @@ -675,6 +754,8 @@ public class PhoneSwitcher extends Handler { mPhoneSubscriptions = copyOf(mPhoneSubscriptions, mActiveModemCount); mPhoneStates = copyOf(mPhoneStates, mActiveModemCount); //clear the list in case of multisim config change mCurrentDdsSwitchFailure.clear(); // Single SIM -> dual SIM switch. for (int phoneId = oldActiveModemCount; phoneId < mActiveModemCount; phoneId++) { Loading @@ -691,6 +772,9 @@ public class PhoneSwitcher extends Handler { } phone.getDataEnabledSettings().registerForDataEnabledChanged( this, EVENT_DATA_ENABLED_CHANGED, null); Set<CommandException.Error> ddsFailure = new HashSet<CommandException.Error>(); mCurrentDdsSwitchFailure.add(ddsFailure); } } Loading Loading @@ -947,11 +1031,6 @@ public class PhoneSwitcher extends Handler { activate(phoneId); } } notifyPreferredDataSubIdChanged(); // Notify all registrants. mActivePhoneRegistrants.notifyRegistrants(); } return diffDetected; } Loading Loading @@ -1021,7 +1100,10 @@ public class PhoneSwitcher extends Handler { } protected void sendRilCommands(int phoneId) { if (!SubscriptionManager.isValidPhoneId(phoneId)) return; if (!SubscriptionManager.isValidPhoneId(phoneId)) { log("sendRilCommands: skip dds switch due to invalid phoneid=" + phoneId); return; } Message message = Message.obtain(this, EVENT_MODEM_COMMAND_DONE, phoneId); if (mHalCommandToUse == HAL_COMMAND_ALLOW_DATA || mHalCommandToUse == HAL_COMMAND_UNKNOWN) { Loading Loading @@ -1455,4 +1537,63 @@ public class PhoneSwitcher extends Handler { mLocalLog.dump(fd, pw, args); pw.decreaseIndent(); } private boolean isAnyVoiceCallActiveOnDevice() { boolean ret = mPhoneIdInVoiceCall != SubscriptionManager.INVALID_PHONE_INDEX; log("isAnyVoiceCallActiveOnDevice: " + ret); return ret; } private void onDdsSwitchResponse(AsyncResult ar, int phoneId) { if (ar.exception != null) { log("onDdsSwitchResponse: DDS switch failed. with exception " + ar.exception); if (ar.exception instanceof CommandException) { CommandException.Error error = ((CommandException) (ar.exception)).getCommandError(); mCurrentDdsSwitchFailure.get(phoneId).add(error); if (error == CommandException.Error.OP_NOT_ALLOWED_DURING_VOICE_CALL) { log("onDdsSwitchResponse: Wait for call end indication"); return; } else if (error == CommandException.Error.INVALID_SIM_STATE) { /* If there is a attach failure due to sim not ready then hold the retry until sim gets ready */ log("onDdsSwitchResponse: Wait for SIM to get READY"); return; } } log("onDdsSwitchResponse: Scheduling DDS switch retry"); sendMessageDelayed(Message.obtain(this, EVENT_MODEM_COMMAND_RETRY, phoneId), MODEM_COMMAND_RETRY_PERIOD_MS); } else { log("onDdsSwitchResponse: DDS switch success on phoneId = " + phoneId); mCurrentDdsSwitchFailure.get(phoneId).clear(); // Notify all registrants mActivePhoneRegistrants.notifyRegistrants(); notifyPreferredDataSubIdChanged(); } } private boolean isPhoneIdValidForRetry(int phoneId) { int phoneIdForRequest = INVALID_PHONE_INDEX; int ddsPhoneId = mSubscriptionController.getPhoneId( mSubscriptionController.getDefaultDataSubId()); if (ddsPhoneId != INVALID_PHONE_INDEX && ddsPhoneId == phoneId) { return true; } else { if (mPrioritizedDcRequests.size() == 0) { return false; } for (int i = 0; i < mMaxDataAttachModemCount; i++) { DcRequest dcRequest = mPrioritizedDcRequests.get(i); if (dcRequest != null) { phoneIdForRequest = phoneIdForRequest(dcRequest.networkRequest); if (phoneIdForRequest == phoneId) { return true; } } } } return false; } }
tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java +115 −5 File changed.Preview size limit exceeded, changes collapsed. Show changes