Merge "Telephony plumbing for SIM call manager voice status"
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index ca6b37a..a247ff1 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -264,6 +264,9 @@
private int mRilVersion;
private boolean mBroadcastEmergencyCallStateChanges = false;
+ private @ServiceState.RegState int mTelecomVoiceServiceStateOverride =
+ ServiceState.STATE_OUT_OF_SERVICE;
+
private CarrierKeyDownloadManager mCDM;
private CarrierInfoManager mCIM;
@@ -600,19 +603,19 @@
@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();
}
}
@@ -1093,28 +1096,48 @@
}
/**
- * 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) {
+ // 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.
+ 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);
- // 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
+ newSs.setVoiceRegState(finalVoiceSs);
+ newSs.setEmergencyOnly(false); // Must be IN_SERVICE if we're here
return newSs;
}
@@ -4263,6 +4286,10 @@
}
pw.println(" isCspPlmnEnabled()=" + isCspPlmnEnabled());
pw.println(" mManualNetworkSelectionPlmn=" + mManualNetworkSelectionPlmn);
+ pw.println(
+ " mTelecomVoiceServiceStateOverride=" + mTelecomVoiceServiceStateOverride + "("
+ + ServiceState.rilServiceStateToString(mTelecomVoiceServiceStateOverride)
+ + ")");
pw.flush();
}
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index f8f0037..e05e861 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -1867,6 +1867,15 @@
}
/**
+ * 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.
*
* @return {@code true} only if thermal mitigation is one of the reason for which radio is off.
@@ -4062,19 +4071,6 @@
}
/**
- * 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.
*/
public boolean setOperatorBrandOverride(String brand) {
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index c01d7bd..a8b1fe1 100755
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -286,6 +286,9 @@
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.
@@ -1735,6 +1738,15 @@
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;
@@ -5288,6 +5300,11 @@
}
}
+ /** 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) {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
index d00c3e1..b16db37 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
@@ -1606,4 +1606,37 @@
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());
+ }
}