Ensure Radio is on before dialing an emergency number.
Code got into a state where we were creating a Connection object to
return synchronously and then starting the Emergency Call helper after
that. The problem is that the synchronous creation code kicked off a
"placeCall" attempt which would fail because airplane mode would be on.
We still turned on the radio but it was too late.
This change makes it so that the synchronous Connection creation is NOT
tied to the placing of a call. Instead, we create the connection and if
it is a non-emergency call, place it, otherwise, start the emergency
call helper and wait for that to place the call.
It required that the telephony-Connection object not be set in the
constructor but instead be set through setOriginalConnection().
Bug: 16885688
Change-Id: I4acf62d34b710c2fe3439fead33b06078f5a36bf
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 6a292c5..7bd43b2 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -164,22 +164,9 @@
private int mAudioQuality;
protected TelephonyConnection(com.android.internal.telephony.Connection originalConnection) {
- Log.v(this, "new TelephonyConnection, originalConnection: " + originalConnection);
- mOriginalConnection = originalConnection;
- getPhone().registerForPreciseCallStateChanged(
- mHandler, MSG_PRECISE_CALL_STATE_CHANGED, null);
- getPhone().registerForRingbackTone(mHandler, MSG_RINGBACK_TONE, null);
- mOriginalConnection.addPostDialListener(mPostDialListener);
- mOriginalConnection.addListener(mOriginalConnectionListener);
-
- // Set video state and capabilities
- setVideoState(mOriginalConnection.getVideoState());
- setLocalVideoCapable(mOriginalConnection.isLocalVideoCapable());
- setRemoteVideoCapable(mOriginalConnection.isRemoteVideoCapable());
- setVideoCallProvider(mOriginalConnection.getVideoCallProvider());
- setAudioQuality(mOriginalConnection.getAudioQuality());
-
- updateHandle();
+ if (originalConnection != null) {
+ setOriginalConnection(originalConnection);
+ }
}
@Override
@@ -356,6 +343,25 @@
// Subclass can override this to do cleanup.
}
+ void setOriginalConnection(com.android.internal.telephony.Connection originalConnection) {
+ Log.v(this, "new TelephonyConnection, originalConnection: " + originalConnection);
+ mOriginalConnection = originalConnection;
+ getPhone().registerForPreciseCallStateChanged(
+ mHandler, MSG_PRECISE_CALL_STATE_CHANGED, null);
+ getPhone().registerForRingbackTone(mHandler, MSG_RINGBACK_TONE, null);
+ mOriginalConnection.addPostDialListener(mPostDialListener);
+ mOriginalConnection.addListener(mOriginalConnectionListener);
+
+ // Set video state and capabilities
+ setVideoState(mOriginalConnection.getVideoState());
+ setLocalVideoCapable(mOriginalConnection.isLocalVideoCapable());
+ setRemoteVideoCapable(mOriginalConnection.isRemoteVideoCapable());
+ setVideoCallProvider(mOriginalConnection.getVideoCallProvider());
+ setAudioQuality(mOriginalConnection.getAudioQuality());
+
+ updateHandle();
+ }
+
private void hangup(int disconnectCause) {
if (mOriginalConnection != null) {
try {
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index e9c83db..7868c72 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -110,12 +110,15 @@
}
}
+ final TelephonyConnection connection = createConnectionFor(phone.getPhoneType(), null);
+ if (connection == null) {
+ return Connection.getFailedConnection(
+ DisconnectCause.OUTGOING_FAILURE, "Invalid phone type");
+ }
+ connection.setHandle(handle, PhoneConstants.PRESENTATION_ALLOWED);
+ connection.setInitializing();
+
if (isEmergencyNumber) {
- final Connection emergencyConnection = startOutgoingCall(request, phone, number);
-
- // Start the emergency call in the initializing state to wait for the radio to spin up.
- emergencyConnection.setInitializing();
-
Log.d(this, "onCreateOutgoingConnection, doing startTurnOnRadioSequence for " +
"emergency number");
if (mEmergencyCallHelper == null) {
@@ -126,19 +129,21 @@
@Override
public void onComplete(boolean isRadioReady) {
if (isRadioReady) {
- emergencyConnection.setInitialized();
+ connection.setInitialized();
+ placeOutgoingConnection(connection, phone, request);
} else {
Log.d(this, "onCreateOutgoingConnection, failed to turn on radio");
- emergencyConnection.setFailed(DisconnectCause.POWER_OFF,
+ connection.setFailed(DisconnectCause.POWER_OFF,
"Failed to turn on radio.");
}
}
});
- return emergencyConnection;
+ } else {
+ placeOutgoingConnection(connection, phone, request);
}
- return startOutgoingCall(request, phone, number);
+ return connection;
}
@Override
@@ -179,32 +184,25 @@
return Connection.getCanceledConnection();
}
- TelephonyConnection connection = null;
- if (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) {
- connection = new GsmConnection(originalConnection);
- } else if (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
- connection = new CdmaConnection(originalConnection);
+ Connection connection = createConnectionFor(phone.getPhoneType(), originalConnection);
+ if (connection == null) {
+ connection = Connection.getCanceledConnection();
}
- if (connection == null) {
- return Connection.getCanceledConnection();
- } else {
- return connection;
- }
+ return connection;
}
- private Connection startOutgoingCall(
- ConnectionRequest request,
- Phone phone,
- String number) {
- Log.v(this, "startOutgoingCall");
+ private void placeOutgoingConnection(
+ TelephonyConnection connection, Phone phone, ConnectionRequest request) {
+ String number = connection.getHandle().getSchemeSpecificPart();
com.android.internal.telephony.Connection originalConnection;
try {
originalConnection = phone.dial(number, request.getVideoState());
} catch (CallStateException e) {
- Log.e(this, e, "startOutgoingCall, phone.dial exception: " + e);
- return Connection.getFailedConnection(DisconnectCause.OUTGOING_FAILURE, e.getMessage());
+ Log.e(this, e, "placeOutgoingConnection, phone.dial exception: " + e);
+ connection.setFailed(DisconnectCause.OUTGOING_FAILURE, e.getMessage());
+ return;
}
if (originalConnection == null) {
@@ -214,19 +212,21 @@
if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM) {
disconnectCause = DisconnectCause.DIALED_MMI;
}
- Log.d(this, "startOutgoingCall, phone.dial returned null");
- return Connection.getFailedConnection(disconnectCause, "Connection is null");
+ Log.d(this, "placeOutgoingConnection, phone.dial returned null");
+ connection.setFailed(disconnectCause, "Connection is null");
+ } else {
+ connection.setOriginalConnection(originalConnection);
}
+ }
- if (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) {
+ private TelephonyConnection createConnectionFor(
+ int phoneType, com.android.internal.telephony.Connection originalConnection) {
+ if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
return new GsmConnection(originalConnection);
- } else if (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
+ } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
return new CdmaConnection(originalConnection);
} else {
- // TODO: Tear down 'originalConnection' here, or move recognition of
- // getPhoneType() earlier in this method before we've already asked phone to dial()
- return Connection.getFailedConnection(DisconnectCause.OUTGOING_FAILURE,
- "Invalid phone type");
+ return null;
}
}