ACTIVE->HOLD happens before HOLD->ACTIVE
Make sure that existing active calls get their states updated first
before we activate any new calls. This ensures that there never exist
more than 1 active call.
Bluetooth PTS certfication test TC_AG_TWC_BV_03_I fails. This test
verifies the ability to swap a background and a foreground call. Per the
spec, this test expects that the active call is first put on hold and
then previously held call is activated.
The telephony layer was doing that in the lower layers,
but due to order of call-state-change notifications,
we weren't guaranteed the order of ACTIVE->HOLD vs
HOLD->ACTIVE. This change makes that deterministic by ensuring that
simultaneous call-state changes always update previously ACTIVE calls
before updating new calls to ACTIVE.
Bug: 17991921
Change-Id: I4e4789c044d9e3614f42143cfa6053881a6d109b
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 1cc6ad6..53d9681 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -498,7 +498,7 @@
case IDLE:
break;
case ACTIVE:
- setActive();
+ setActiveInternal();
break;
case HOLDING:
setOnHold();
@@ -524,6 +524,31 @@
updateAddress();
}
+ private void setActiveInternal() {
+ if (getState() == STATE_ACTIVE) {
+ Log.w(this, "Should not be called if this is already ACTIVE");
+ return;
+ }
+
+ // When we set a call to active, we need to make sure that there are no other active
+ // calls. However, the ordering of state updates to connections can be non-deterministic
+ // since all connections register for state changes on the phone independently.
+ // To "optimize", we check here to see if there already exists any active calls. If so,
+ // we issue an update for those calls first to make sure we only have one top-level
+ // active call.
+ if (getConnectionService() != null) {
+ for (Connection current : getConnectionService().getAllConnections()) {
+ if (current != this && current instanceof TelephonyConnection) {
+ TelephonyConnection other = (TelephonyConnection) current;
+ if (other.getState() == STATE_ACTIVE) {
+ other.updateState();
+ }
+ }
+ }
+ }
+ setActive();
+ }
+
private void close() {
Log.v(this, "close");
if (getPhone() != null) {