Perform clean up when a call-service dies.
Also add some test call service logic to make this logic
easily testable.
Bug: 13546896
Change-Id: I7e1518488b4cd2d7752c3fee32816cecf734e388
diff --git a/src/com/android/telecomm/CallServiceAdapter.java b/src/com/android/telecomm/CallServiceAdapter.java
index e30d338..f95953a 100644
--- a/src/com/android/telecomm/CallServiceAdapter.java
+++ b/src/com/android/telecomm/CallServiceAdapter.java
@@ -23,7 +23,9 @@
import com.android.internal.telecomm.ICallServiceAdapter;
import com.google.android.collect.Sets;
import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import java.util.Collections;
import java.util.Set;
/**
@@ -222,6 +224,35 @@
}
/**
+ * Called when the associated call service dies.
+ */
+ void handleCallServiceDeath() {
+ if (!mPendingIncomingCallIds.isEmpty()) {
+ // Here and in the for loop below, we need to iterate through a copy because the code
+ // inside the loop will modify the original list.
+ for (String callId : ImmutableList.copyOf(mPendingIncomingCallIds)) {
+ mIncomingCallsManager.handleFailedIncomingCall(callId);
+ }
+
+ if (!mPendingIncomingCallIds.isEmpty()) {
+ Log.wtf(this, "Pending incoming calls did not get cleared.");
+ mPendingIncomingCallIds.clear();
+ }
+ }
+
+ if (!mPendingOutgoingCallIds.isEmpty()) {
+ for (String callId : ImmutableList.copyOf(mPendingOutgoingCallIds)) {
+ mOutgoingCallsManager.handleFailedCallAttempt(callId, "Call service disconnected.");
+ }
+
+ if (!mPendingOutgoingCallIds.isEmpty()) {
+ Log.wtf(this, "Pending outgoing calls did not get cleared.");
+ mPendingOutgoingCallIds.clear();
+ }
+ }
+ }
+
+ /**
* Throws an IllegalArgumentException if the specified call ID is invalid.
*
* @param callId The call ID to check.
diff --git a/src/com/android/telecomm/CallServiceWrapper.java b/src/com/android/telecomm/CallServiceWrapper.java
index 426a019..46e99cb 100644
--- a/src/com/android/telecomm/CallServiceWrapper.java
+++ b/src/com/android/telecomm/CallServiceWrapper.java
@@ -85,6 +85,7 @@
* @param errorCallback The callback to invoke upon failure.
*/
void isCompatibleWith(final CallInfo callInfo, final Runnable errorCallback) {
+ Log.d(this, "isCompatibleWith(%s) via %s.", callInfo, getComponentName());
BindCallback callback = new BindCallback() {
@Override public void onSuccess() {
if (isServiceValid("isCompatibleWith")) {
@@ -113,6 +114,7 @@
* @param errorCallback The callback to invoke upon failure.
*/
void call(final CallInfo callInfo, final Runnable errorCallback) {
+ Log.d(this, "call(%s) via %s.", callInfo, getComponentName());
BindCallback callback = new BindCallback() {
@Override public void onSuccess() {
String callId = callInfo.getId();
@@ -181,6 +183,7 @@
final Bundle extras,
final Runnable errorCallback) {
+ Log.d(this, "setIncomingCall(%s) via %s.", callId, getComponentName());
BindCallback callback = new BindCallback() {
@Override public void onSuccess() {
if (isServiceValid("setIncomingCallId")) {
@@ -257,7 +260,17 @@
/** {@inheritDoc} */
@Override protected void setServiceInterface(IBinder binder) {
- mServiceInterface = ICallService.Stub.asInterface(binder);
- setCallServiceAdapter(mAdapter);
+ if (binder == null) {
+ // We have lost our service connection. Notify the world that this call service is done.
+ // We must notify the adapter before CallsManager. The adapter will force any pending
+ // outgoing calls to try the next call service. This needs to happen before CallsManager
+ // tries to clean up any calls still associated with this call service.
+ mAdapter.handleCallServiceDeath();
+ CallsManager.getInstance().handleCallServiceDeath(this);
+ mServiceInterface = null;
+ } else {
+ mServiceInterface = ICallService.Stub.asInterface(binder);
+ setCallServiceAdapter(mAdapter);
+ }
}
}
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index 92c247e..36fbf77 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -350,6 +350,21 @@
}
/**
+ * Cleans up any calls currently associated with the specified call service when the
+ * call-service binder disconnects unexpectedly.
+ *
+ * @param callService The call service that disconnected.
+ */
+ void handleCallServiceDeath(CallServiceWrapper callService) {
+ Preconditions.checkNotNull(callService);
+ for (Call call : ImmutableList.copyOf(mCalls.values())) {
+ if (call.getCallService() == callService) {
+ markCallAsDisconnected(call.getId());
+ }
+ }
+ }
+
+ /**
* Adds the specified call to the main list of live calls.
*
* @param call The call to add.
diff --git a/src/com/android/telecomm/IncomingCallsManager.java b/src/com/android/telecomm/IncomingCallsManager.java
index 6edbbbf..0d98dc4 100644
--- a/src/com/android/telecomm/IncomingCallsManager.java
+++ b/src/com/android/telecomm/IncomingCallsManager.java
@@ -63,7 +63,7 @@
Runnable errorCallback = new Runnable() {
@Override public void run() {
- handleFailedIncomingCall(call);
+ handleFailedIncomingCall(callId);
}
};
@@ -89,12 +89,13 @@
/**
* Notifies switchboard of the failed incoming call after removing it from the pending list.
*
- * @param call The call.
+ * @param callId The ID of the call.
*/
- private void handleFailedIncomingCall(Call call) {
+ void handleFailedIncomingCall(String callId) {
ThreadUtil.checkOnMainThread();
- if (mPendingIncomingCalls.remove(call.getId()) != null) {
+ Call call = mPendingIncomingCalls.remove(callId);
+ if (call != null) {
Log.i(this, "Failed to get details for incoming call %s", call);
// The call was found still waiting for details. Consider it failed.
mSwitchboard.handleFailedIncomingCall(call);
diff --git a/tests/src/com/android/telecomm/testcallservice/DummyCallServiceSelector.java b/tests/src/com/android/telecomm/testcallservice/DummyCallServiceSelector.java
index 98dc190..dfcb6fd 100644
--- a/tests/src/com/android/telecomm/testcallservice/DummyCallServiceSelector.java
+++ b/tests/src/com/android/telecomm/testcallservice/DummyCallServiceSelector.java
@@ -20,6 +20,8 @@
import android.telecomm.CallServiceDescriptor;
import android.telecomm.CallServiceSelector;
+import com.google.common.collect.Lists;
+
import java.util.List;
/**
@@ -37,6 +39,16 @@
CallInfo callInfo, List<CallServiceDescriptor> callServiceDescriptors,
CallServiceSelectionResponse response) {
- response.setSelectedCallServices(callServiceDescriptors);
+ List<CallServiceDescriptor> orderedList = Lists.newLinkedList();
+
+ // Make sure that the test call services are the only ones
+ for (CallServiceDescriptor descriptor : callServiceDescriptors) {
+ String packageName = descriptor.getServiceComponent().getPackageName();
+ if (getPackageName().equals(packageName)) {
+ orderedList.add(descriptor);
+ }
+ }
+
+ response.setSelectedCallServices(orderedList);
}
}
diff --git a/tests/src/com/android/telecomm/testcallservice/TestCallService.java b/tests/src/com/android/telecomm/testcallservice/TestCallService.java
index d3c44a8..d4e07e7 100644
--- a/tests/src/com/android/telecomm/testcallservice/TestCallService.java
+++ b/tests/src/com/android/telecomm/testcallservice/TestCallService.java
@@ -64,12 +64,7 @@
mTelecommAdapter = callServiceAdapter;
mLiveCallIds = Sets.newHashSet();
- // Prepare the media player to play a tone when there is a call.
- mMediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.beep_boop);
- mMediaPlayer.setLooping(true);
-
- // TODO(santoscordon): Re-enable audio through voice-call stream.
- //mMediaPlayer.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);
+ mMediaPlayer = createMediaPlayer();
}
/**
@@ -101,7 +96,13 @@
*/
@Override
public void call(CallInfo callInfo) {
- Log.i(TAG, "call(" + callInfo + ")");
+ String number = callInfo.getHandle().getSchemeSpecificPart();
+ Log.i(TAG, "call(" + number + ")");
+
+ // Crash on 555-DEAD to test call service crashing.
+ if ("5550340".equals(number)) {
+ throw new RuntimeException("Goodbye, cruel world.");
+ }
createCall(callInfo.getId());
mTelecommAdapter.handleSuccessfulOutgoingCall(callInfo.getId());
@@ -130,6 +131,7 @@
@Override
public void answer(String callId) {
mTelecommAdapter.setActive(callId);
+ createCall(callId);
}
/** {@inheritDoc} */
@@ -198,6 +200,16 @@
// Stops audio if there are no more calls.
if (mLiveCallIds.isEmpty() && mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
+ mMediaPlayer.release();
+ mMediaPlayer = createMediaPlayer();
}
}
+
+ private MediaPlayer createMediaPlayer() {
+ // Prepare the media player to play a tone when there is a call.
+ MediaPlayer mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.beep_boop);
+ mediaPlayer.setLooping(true);
+ return mediaPlayer;
+ }
+
}