Loading src/java/com/android/internal/telephony/GsmCdmaPhone.java +54 −27 Original line number Diff line number Diff line Loading @@ -264,6 +264,9 @@ public class GsmCdmaPhone extends Phone { private int mRilVersion; private boolean mBroadcastEmergencyCallStateChanges = false; private @ServiceState.RegState int mTelecomVoiceServiceStateOverride = ServiceState.STATE_OUT_OF_SERVICE; private CarrierKeyDownloadManager mCDM; private CarrierInfoManager mCIM; Loading Loading @@ -600,19 +603,19 @@ public class GsmCdmaPhone extends Phone { @Override @NonNull public ServiceState getServiceState() { if (mSST == null || mSST.mSS.getState() != ServiceState.STATE_IN_SERVICE) { if (mImsPhone != null) { return mergeServiceStates((mSST == null) ? new ServiceState() : mSST.getServiceState(), mImsPhone.getServiceState()); } ServiceState baseSs = mSST != null ? mSST.getServiceState() : new ServiceState(); ServiceState imsSs = mImsPhone != null ? mImsPhone.getServiceState() : new ServiceState(); return mergeVoiceServiceStates(baseSs, imsSs, mTelecomVoiceServiceStateOverride); } if (mSST != null) { return mSST.getServiceState(); } else { // avoid potential NPE in EmergencyCallHelper during Phone switch return new ServiceState(); @Override public void setVoiceServiceStateOverride(boolean hasService) { int newOverride = hasService ? ServiceState.STATE_IN_SERVICE : ServiceState.STATE_OUT_OF_SERVICE; boolean changed = newOverride != mTelecomVoiceServiceStateOverride; mTelecomVoiceServiceStateOverride = newOverride; if (changed && mSST != null) { mSST.onTelecomVoiceServiceStateOverrideChanged(); } } Loading Loading @@ -1093,28 +1096,48 @@ public class GsmCdmaPhone extends Phone { } /** * ImsService reports "IN_SERVICE" for its voice registration state even if the device * has lost the physical link to the tower. This helper method merges the IMS and modem * ServiceState, only overriding the voice registration state when we are registered to IMS. In * this case the voice registration state may be "OUT_OF_SERVICE", so override the voice * registration state with the data registration state. * Amends {@code baseSs} if its voice registration state is {@code OUT_OF_SERVICE}. * * <p>Even if the device has lost the CS link to the tower, there are two potential additional * sources of voice capability not directly saved inside ServiceStateTracker: * * <ul> * <li>IMS voice registration state ({@code imsSs}) - if this is {@code IN_SERVICE} for voice, * we substite {@code baseSs#getDataRegState} as the final voice service state (ImsService * reports {@code IN_SERVICE} for its voice registration state even if the device has lost * the physical link to the tower) * <li>OTT voice capability provided through telecom ({@code telecomSs}) - if this is {@code * IN_SERVICE}, we directly substitute it as the final voice service state * </ul> */ private ServiceState mergeServiceStates(ServiceState baseSs, ServiceState imsSs) { // No need to merge states if the baseSs is IN_SERVICE. private static ServiceState mergeVoiceServiceStates( ServiceState baseSs, ServiceState imsSs, @ServiceState.RegState int telecomSs) { if (baseSs.getState() == ServiceState.STATE_IN_SERVICE) { // No need to merge states if the baseSs is IN_SERVICE. return baseSs; } // "IN_SERVICE" in this case means IMS is registered. if (imsSs.getState() != ServiceState.STATE_IN_SERVICE) { return baseSs; } ServiceState newSs = new ServiceState(baseSs); // If any of the following additional sources are IN_SERVICE, we use that since voice calls // can be routed through something other than the CS link. @ServiceState.RegState int finalVoiceSs = ServiceState.STATE_OUT_OF_SERVICE; if (telecomSs == ServiceState.STATE_IN_SERVICE) { // If telecom reports there's a PhoneAccount that can provide voice service // (CAPABILITY_VOICE_CALLING_AVAILABLE), then we trust that info as it may account for // external possibilities like wi-fi calling provided by the SIM call manager app. Note // that CAPABILITY_PLACE_EMERGENCY_CALLS is handled separately. finalVoiceSs = telecomSs; } else if (imsSs.getState() == ServiceState.STATE_IN_SERVICE) { // Voice override for IMS case. In this case, voice registration is OUT_OF_SERVICE, but // IMS is available, so use data registration state as a basis for determining // whether or not the physical link is available. newSs.setVoiceRegState(baseSs.getDataRegistrationState()); newSs.setEmergencyOnly(false); // only get here if voice is IN_SERVICE finalVoiceSs = baseSs.getDataRegistrationState(); } if (finalVoiceSs != ServiceState.STATE_IN_SERVICE) { // None of the additional sources provide a usable route, and they only use IN/OUT. return baseSs; } ServiceState newSs = new ServiceState(baseSs); newSs.setVoiceRegState(finalVoiceSs); newSs.setEmergencyOnly(false); // Must be IN_SERVICE if we're here return newSs; } Loading Loading @@ -4263,6 +4286,10 @@ public class GsmCdmaPhone extends Phone { } pw.println(" isCspPlmnEnabled()=" + isCspPlmnEnabled()); pw.println(" mManualNetworkSelectionPlmn=" + mManualNetworkSelectionPlmn); pw.println( " mTelecomVoiceServiceStateOverride=" + mTelecomVoiceServiceStateOverride + "(" + ServiceState.rilServiceStateToString(mTelecomVoiceServiceStateOverride) + ")"); pw.flush(); } Loading src/java/com/android/internal/telephony/Phone.java +9 −13 Original line number Diff line number Diff line Loading @@ -1866,6 +1866,15 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return null; } /** * Override to merge into {@link #getServiceState} when telecom has registered a SIM call * manager that supports over-the-top SIM-based calling (e.g. carrier-provided wi-fi calling * implementation). * * @param hasService Whether or not the SIM call manager currently provides over-the-top voice */ public void setVoiceServiceStateOverride(boolean hasService) {} /** * Check whether the radio is off for thermal reason. * Loading Loading @@ -4061,19 +4070,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return mPhoneId; } /** * Return the service state of mImsPhone if it is STATE_IN_SERVICE * otherwise return the current voice service state */ public int getVoicePhoneServiceState() { Phone imsPhone = mImsPhone; if (imsPhone != null && imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE) { return ServiceState.STATE_IN_SERVICE; } return getServiceState().getState(); } /** * Override the service provider name and the operator name for the current ICCID. */ Loading src/java/com/android/internal/telephony/ServiceStateTracker.java +17 −0 Original line number Diff line number Diff line Loading @@ -286,6 +286,9 @@ public class ServiceStateTracker extends Handler { private static final int EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT = 62; protected static final int EVENT_RESET_LAST_KNOWN_CELL_IDENTITY = 63; private static final int EVENT_REGISTER_DATA_NETWORK_EXISTING_CHANGED = 64; // Telecom has un/registered a PhoneAccount that provides OTT voice calling capability, e.g. // wi-fi calling. protected static final int EVENT_TELECOM_VOICE_SERVICE_STATE_OVERRIDE_CHANGED = 65; /** * The current service state. Loading Loading @@ -1735,6 +1738,15 @@ public class ServiceStateTracker extends Handler { break; } case EVENT_TELECOM_VOICE_SERVICE_STATE_OVERRIDE_CHANGED: if (DBG) log("EVENT_TELECOM_VOICE_SERVICE_STATE_OVERRIDE_CHANGED"); // Similar to IMS, OTT voice state will only affect the merged service state if the // CS voice service state of GsmCdma phone is not STATE_IN_SERVICE. if (mSS.getState() != ServiceState.STATE_IN_SERVICE) { mPhone.notifyServiceStateChanged(mPhone.getServiceState()); } break; default: log("Unhandled message with number: " + msg.what); break; Loading Loading @@ -5288,6 +5300,11 @@ public class ServiceStateTracker extends Handler { } } /** Called when telecom has reported a voice service state change. */ public void onTelecomVoiceServiceStateOverrideChanged() { sendMessage(obtainMessage(EVENT_TELECOM_VOICE_SERVICE_STATE_OVERRIDE_CHANGED)); } private void dumpCellInfoList(PrintWriter pw) { pw.print(" mLastCellInfoList={"); if(mLastCellInfoList != null) { Loading tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +33 −0 Original line number Diff line number Diff line Loading @@ -1606,4 +1606,37 @@ public class GsmCdmaPhoneTest extends TelephonyTest { mPhoneUT.setImsPhone(mImsPhone); } @Test public void testSetVoiceServiceStateOverride() throws Exception { // Start with CS voice and IMS both OOS, no override ServiceState csServiceState = new ServiceState(); csServiceState.setStateOutOfService(); csServiceState.setDataRegState(ServiceState.STATE_IN_SERVICE); doReturn(csServiceState).when(mSST).getServiceState(); ServiceState imsServiceState = new ServiceState(); imsServiceState.setStateOutOfService(); doReturn(imsServiceState).when(mImsPhone).getServiceState(); replaceInstance(Phone.class, "mImsPhone", mPhoneUT, mImsPhone); assertEquals(ServiceState.STATE_OUT_OF_SERVICE, mPhoneUT.getServiceState().getState()); // Now set the telecom override mPhoneUT.setVoiceServiceStateOverride(true); verify(mSST).onTelecomVoiceServiceStateOverrideChanged(); assertEquals(ServiceState.STATE_IN_SERVICE, mPhoneUT.getServiceState().getState()); // IMS and telecom voice are treated as equivalent for merging purposes imsServiceState.setVoiceRegState(ServiceState.STATE_IN_SERVICE); assertEquals(ServiceState.STATE_IN_SERVICE, mPhoneUT.getServiceState().getState()); // Clearing the telecom override still lets IMS override separately mPhoneUT.setVoiceServiceStateOverride(false); verify(mSST, times(2)).onTelecomVoiceServiceStateOverrideChanged(); assertEquals(ServiceState.STATE_IN_SERVICE, mPhoneUT.getServiceState().getState()); // And now removing the IMS IN_SERVICE results in the base OOS showing through imsServiceState.setStateOutOfService(); assertEquals(ServiceState.STATE_OUT_OF_SERVICE, mPhoneUT.getServiceState().getState()); } } Loading
src/java/com/android/internal/telephony/GsmCdmaPhone.java +54 −27 Original line number Diff line number Diff line Loading @@ -264,6 +264,9 @@ public class GsmCdmaPhone extends Phone { private int mRilVersion; private boolean mBroadcastEmergencyCallStateChanges = false; private @ServiceState.RegState int mTelecomVoiceServiceStateOverride = ServiceState.STATE_OUT_OF_SERVICE; private CarrierKeyDownloadManager mCDM; private CarrierInfoManager mCIM; Loading Loading @@ -600,19 +603,19 @@ public class GsmCdmaPhone extends Phone { @Override @NonNull public ServiceState getServiceState() { if (mSST == null || mSST.mSS.getState() != ServiceState.STATE_IN_SERVICE) { if (mImsPhone != null) { return mergeServiceStates((mSST == null) ? new ServiceState() : mSST.getServiceState(), mImsPhone.getServiceState()); } ServiceState baseSs = mSST != null ? mSST.getServiceState() : new ServiceState(); ServiceState imsSs = mImsPhone != null ? mImsPhone.getServiceState() : new ServiceState(); return mergeVoiceServiceStates(baseSs, imsSs, mTelecomVoiceServiceStateOverride); } if (mSST != null) { return mSST.getServiceState(); } else { // avoid potential NPE in EmergencyCallHelper during Phone switch return new ServiceState(); @Override public void setVoiceServiceStateOverride(boolean hasService) { int newOverride = hasService ? ServiceState.STATE_IN_SERVICE : ServiceState.STATE_OUT_OF_SERVICE; boolean changed = newOverride != mTelecomVoiceServiceStateOverride; mTelecomVoiceServiceStateOverride = newOverride; if (changed && mSST != null) { mSST.onTelecomVoiceServiceStateOverrideChanged(); } } Loading Loading @@ -1093,28 +1096,48 @@ public class GsmCdmaPhone extends Phone { } /** * ImsService reports "IN_SERVICE" for its voice registration state even if the device * has lost the physical link to the tower. This helper method merges the IMS and modem * ServiceState, only overriding the voice registration state when we are registered to IMS. In * this case the voice registration state may be "OUT_OF_SERVICE", so override the voice * registration state with the data registration state. * Amends {@code baseSs} if its voice registration state is {@code OUT_OF_SERVICE}. * * <p>Even if the device has lost the CS link to the tower, there are two potential additional * sources of voice capability not directly saved inside ServiceStateTracker: * * <ul> * <li>IMS voice registration state ({@code imsSs}) - if this is {@code IN_SERVICE} for voice, * we substite {@code baseSs#getDataRegState} as the final voice service state (ImsService * reports {@code IN_SERVICE} for its voice registration state even if the device has lost * the physical link to the tower) * <li>OTT voice capability provided through telecom ({@code telecomSs}) - if this is {@code * IN_SERVICE}, we directly substitute it as the final voice service state * </ul> */ private ServiceState mergeServiceStates(ServiceState baseSs, ServiceState imsSs) { // No need to merge states if the baseSs is IN_SERVICE. private static ServiceState mergeVoiceServiceStates( ServiceState baseSs, ServiceState imsSs, @ServiceState.RegState int telecomSs) { if (baseSs.getState() == ServiceState.STATE_IN_SERVICE) { // No need to merge states if the baseSs is IN_SERVICE. return baseSs; } // "IN_SERVICE" in this case means IMS is registered. if (imsSs.getState() != ServiceState.STATE_IN_SERVICE) { return baseSs; } ServiceState newSs = new ServiceState(baseSs); // If any of the following additional sources are IN_SERVICE, we use that since voice calls // can be routed through something other than the CS link. @ServiceState.RegState int finalVoiceSs = ServiceState.STATE_OUT_OF_SERVICE; if (telecomSs == ServiceState.STATE_IN_SERVICE) { // If telecom reports there's a PhoneAccount that can provide voice service // (CAPABILITY_VOICE_CALLING_AVAILABLE), then we trust that info as it may account for // external possibilities like wi-fi calling provided by the SIM call manager app. Note // that CAPABILITY_PLACE_EMERGENCY_CALLS is handled separately. finalVoiceSs = telecomSs; } else if (imsSs.getState() == ServiceState.STATE_IN_SERVICE) { // Voice override for IMS case. In this case, voice registration is OUT_OF_SERVICE, but // IMS is available, so use data registration state as a basis for determining // whether or not the physical link is available. newSs.setVoiceRegState(baseSs.getDataRegistrationState()); newSs.setEmergencyOnly(false); // only get here if voice is IN_SERVICE finalVoiceSs = baseSs.getDataRegistrationState(); } if (finalVoiceSs != ServiceState.STATE_IN_SERVICE) { // None of the additional sources provide a usable route, and they only use IN/OUT. return baseSs; } ServiceState newSs = new ServiceState(baseSs); newSs.setVoiceRegState(finalVoiceSs); newSs.setEmergencyOnly(false); // Must be IN_SERVICE if we're here return newSs; } Loading Loading @@ -4263,6 +4286,10 @@ public class GsmCdmaPhone extends Phone { } pw.println(" isCspPlmnEnabled()=" + isCspPlmnEnabled()); pw.println(" mManualNetworkSelectionPlmn=" + mManualNetworkSelectionPlmn); pw.println( " mTelecomVoiceServiceStateOverride=" + mTelecomVoiceServiceStateOverride + "(" + ServiceState.rilServiceStateToString(mTelecomVoiceServiceStateOverride) + ")"); pw.flush(); } Loading
src/java/com/android/internal/telephony/Phone.java +9 −13 Original line number Diff line number Diff line Loading @@ -1866,6 +1866,15 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return null; } /** * Override to merge into {@link #getServiceState} when telecom has registered a SIM call * manager that supports over-the-top SIM-based calling (e.g. carrier-provided wi-fi calling * implementation). * * @param hasService Whether or not the SIM call manager currently provides over-the-top voice */ public void setVoiceServiceStateOverride(boolean hasService) {} /** * Check whether the radio is off for thermal reason. * Loading Loading @@ -4061,19 +4070,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return mPhoneId; } /** * Return the service state of mImsPhone if it is STATE_IN_SERVICE * otherwise return the current voice service state */ public int getVoicePhoneServiceState() { Phone imsPhone = mImsPhone; if (imsPhone != null && imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE) { return ServiceState.STATE_IN_SERVICE; } return getServiceState().getState(); } /** * Override the service provider name and the operator name for the current ICCID. */ Loading
src/java/com/android/internal/telephony/ServiceStateTracker.java +17 −0 Original line number Diff line number Diff line Loading @@ -286,6 +286,9 @@ public class ServiceStateTracker extends Handler { private static final int EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT = 62; protected static final int EVENT_RESET_LAST_KNOWN_CELL_IDENTITY = 63; private static final int EVENT_REGISTER_DATA_NETWORK_EXISTING_CHANGED = 64; // Telecom has un/registered a PhoneAccount that provides OTT voice calling capability, e.g. // wi-fi calling. protected static final int EVENT_TELECOM_VOICE_SERVICE_STATE_OVERRIDE_CHANGED = 65; /** * The current service state. Loading Loading @@ -1735,6 +1738,15 @@ public class ServiceStateTracker extends Handler { break; } case EVENT_TELECOM_VOICE_SERVICE_STATE_OVERRIDE_CHANGED: if (DBG) log("EVENT_TELECOM_VOICE_SERVICE_STATE_OVERRIDE_CHANGED"); // Similar to IMS, OTT voice state will only affect the merged service state if the // CS voice service state of GsmCdma phone is not STATE_IN_SERVICE. if (mSS.getState() != ServiceState.STATE_IN_SERVICE) { mPhone.notifyServiceStateChanged(mPhone.getServiceState()); } break; default: log("Unhandled message with number: " + msg.what); break; Loading Loading @@ -5288,6 +5300,11 @@ public class ServiceStateTracker extends Handler { } } /** Called when telecom has reported a voice service state change. */ public void onTelecomVoiceServiceStateOverrideChanged() { sendMessage(obtainMessage(EVENT_TELECOM_VOICE_SERVICE_STATE_OVERRIDE_CHANGED)); } private void dumpCellInfoList(PrintWriter pw) { pw.print(" mLastCellInfoList={"); if(mLastCellInfoList != null) { Loading
tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +33 −0 Original line number Diff line number Diff line Loading @@ -1606,4 +1606,37 @@ public class GsmCdmaPhoneTest extends TelephonyTest { mPhoneUT.setImsPhone(mImsPhone); } @Test public void testSetVoiceServiceStateOverride() throws Exception { // Start with CS voice and IMS both OOS, no override ServiceState csServiceState = new ServiceState(); csServiceState.setStateOutOfService(); csServiceState.setDataRegState(ServiceState.STATE_IN_SERVICE); doReturn(csServiceState).when(mSST).getServiceState(); ServiceState imsServiceState = new ServiceState(); imsServiceState.setStateOutOfService(); doReturn(imsServiceState).when(mImsPhone).getServiceState(); replaceInstance(Phone.class, "mImsPhone", mPhoneUT, mImsPhone); assertEquals(ServiceState.STATE_OUT_OF_SERVICE, mPhoneUT.getServiceState().getState()); // Now set the telecom override mPhoneUT.setVoiceServiceStateOverride(true); verify(mSST).onTelecomVoiceServiceStateOverrideChanged(); assertEquals(ServiceState.STATE_IN_SERVICE, mPhoneUT.getServiceState().getState()); // IMS and telecom voice are treated as equivalent for merging purposes imsServiceState.setVoiceRegState(ServiceState.STATE_IN_SERVICE); assertEquals(ServiceState.STATE_IN_SERVICE, mPhoneUT.getServiceState().getState()); // Clearing the telecom override still lets IMS override separately mPhoneUT.setVoiceServiceStateOverride(false); verify(mSST, times(2)).onTelecomVoiceServiceStateOverrideChanged(); assertEquals(ServiceState.STATE_IN_SERVICE, mPhoneUT.getServiceState().getState()); // And now removing the IMS IN_SERVICE results in the base OOS showing through imsServiceState.setStateOutOfService(); assertEquals(ServiceState.STATE_OUT_OF_SERVICE, mPhoneUT.getServiceState().getState()); } }