Test Call Service: Add handoff support
This CL adds support for switching from TestCallService to
PSTN and back. Pressing one one the keypad enables handoff
and pressing 2 disables handoff.
Change-Id: Ide576c4ed3c45efd8605da5dafc8253f2658893c
diff --git a/tests/src/com/android/telecomm/testcallservice/CallServiceNotifier.java b/tests/src/com/android/telecomm/testcallservice/CallServiceNotifier.java
index a186e58..e88c293 100644
--- a/tests/src/com/android/telecomm/testcallservice/CallServiceNotifier.java
+++ b/tests/src/com/android/telecomm/testcallservice/CallServiceNotifier.java
@@ -26,12 +26,10 @@
import android.util.Log;
/**
- * Class used to create, update and cancel the notification used to display and update call state for
- * {@link TestCallService}.
+ * Class used to create, update and cancel the notification used to display and update call state
+ * for {@link TestCallService}.
*/
public class CallServiceNotifier {
- private static final String TAG = CallServiceNotifier.class.getSimpleName();
-
private static final CallServiceNotifier INSTANCE = new CallServiceNotifier();
/**
@@ -56,7 +54,7 @@
* Updates the notification in the notification pane.
*/
public void updateNotification(Context context) {
- Log.i("CallServiceNotifier", "adding the notification ------------");
+ log("adding the notification ------------");
getNotificationManager(context).notify(CALL_NOTIFICATION_ID, getNotification(context));
}
@@ -64,7 +62,7 @@
* Cancels the notification.
*/
public void cancelNotification(Context context) {
- Log.i(TAG, "canceling notification");
+ log("canceling notification");
getNotificationManager(context).cancel(CALL_NOTIFICATION_ID);
}
@@ -110,7 +108,7 @@
* Creates the intent to add an incoming call through Telecomm.
*/
private PendingIntent createIncomingCallIntent(Context context) {
- Log.i(TAG, "Creating incoming call pending intent.");
+ log("Creating incoming call pending intent.");
// Build descriptor for TestCallService.
CallServiceDescriptor.Builder descriptorBuilder = CallServiceDescriptor.newBuilder(context);
descriptorBuilder.setCallService(TestCallService.class);
@@ -141,4 +139,8 @@
private void addExitAction(Notification.Builder builder, Context context) {
builder.addAction(0, "Exit", createExitIntent(context));
}
+
+ private static void log(String msg) {
+ Log.w("testcallservice", "[CallServiceNotifier] " + msg);
+ }
}
diff --git a/tests/src/com/android/telecomm/testcallservice/DummyCallServiceSelector.java b/tests/src/com/android/telecomm/testcallservice/DummyCallServiceSelector.java
index c267867..86319a4 100644
--- a/tests/src/com/android/telecomm/testcallservice/DummyCallServiceSelector.java
+++ b/tests/src/com/android/telecomm/testcallservice/DummyCallServiceSelector.java
@@ -16,33 +16,100 @@
package com.android.telecomm.testcallservice;
+import android.net.Uri;
+import android.os.Bundle;
import android.telecomm.CallInfo;
import android.telecomm.CallServiceDescriptor;
import android.telecomm.CallServiceSelector;
import android.telecomm.CallServiceSelectorAdapter;
+import android.util.Log;
+import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import java.util.List;
-/**
- * Dummy call-service selector which returns the list of call services in the same order in which it
- * was given. Also returns false for every request on switchability.
- */
+/** Simple selector to exercise Telecomm code. */
public class DummyCallServiceSelector extends CallServiceSelector {
+ private static DummyCallServiceSelector sInstance;
+ private static final String SCHEME_TEL = "tel";
+ private static final String TELEPHONY_PACKAGE_NAME =
+ "com.android.phone";
+ private static final String CUSTOM_HANDOFF_KEY = "custom_handoff_key";
+ private static final String CUSTOM_HANDOFF_VALUE = "custom_handoff_value";
+
+ public DummyCallServiceSelector() {
+ log("constructor");
+ Preconditions.checkState(sInstance == null);
+ sInstance = this;
+ }
+
+ static DummyCallServiceSelector getInstance() {
+ Preconditions.checkNotNull(sInstance);
+ return sInstance;
+ }
@Override
protected void select(CallInfo callInfo, List<CallServiceDescriptor> descriptors) {
+ log("select");
List<CallServiceDescriptor> orderedList = Lists.newLinkedList();
- // Make sure that the test call services are the only ones
+ boolean shouldHandoffToPstn = false;
+ if (callInfo.getCurrentCallServiceDescriptor() != null) {
+ // If the current call service is TestCallService then handoff to PSTN, otherwise
+ // handoff to TestCallService.
+ shouldHandoffToPstn = isTestCallService(callInfo.getCurrentCallServiceDescriptor());
+ String extraValue = callInfo.getExtras().getString(CUSTOM_HANDOFF_KEY);
+ log("handing off, toPstn: " + shouldHandoffToPstn + ", extraValue: " + extraValue);
+ Preconditions.checkState(CUSTOM_HANDOFF_VALUE.equals(extraValue));
+ }
+
for (CallServiceDescriptor descriptor : descriptors) {
- String packageName = descriptor.getServiceComponent().getPackageName();
- if (getPackageName().equals(packageName)) {
+ if (isTestCallService(descriptor) && !shouldHandoffToPstn) {
+ orderedList.add(0, descriptor);
+ } else if (isPstnCallService(descriptor)) {
orderedList.add(descriptor);
+ } else {
+ log("skipping call service: " + descriptor.getServiceComponent());
}
}
getAdapter().setSelectedCallServices(callInfo.getId(), orderedList);
}
+
+ void sendHandoffInfo(Uri remoteHandle, Uri handoffHandle) {
+ log("sendHandoffInfo");
+ String callId = findMatchingCall(remoteHandle);
+ Preconditions.checkNotNull(callId);
+ Bundle extras = new Bundle();
+ extras.putString(CUSTOM_HANDOFF_KEY, CUSTOM_HANDOFF_VALUE);
+ getAdapter().setHandoffInfo(callId, handoffHandle, extras);
+ }
+
+ private String findMatchingCall(Uri remoteHandle) {
+ for (CallInfo callInfo : getCalls()) {
+ if (remoteHandle.equals(callInfo.getOriginalHandle())) {
+ return callInfo.getId();
+ }
+ }
+ return null;
+ }
+
+ private boolean isTestCallService(CallServiceDescriptor descriptor) {
+ if (descriptor == null) {
+ return false;
+ }
+ return getPackageName().equals(descriptor.getServiceComponent().getPackageName());
+ }
+
+ private boolean isPstnCallService(CallServiceDescriptor descriptor) {
+ if (descriptor == null) {
+ return false;
+ }
+ return TELEPHONY_PACKAGE_NAME.equals(descriptor.getServiceComponent().getPackageName());
+ }
+
+ private static void log(String msg) {
+ Log.w("testcallservice", "[DummyCallServiceSelector] " + msg);
+ }
}
diff --git a/tests/src/com/android/telecomm/testcallservice/TestCallService.java b/tests/src/com/android/telecomm/testcallservice/TestCallService.java
index f6e2da7..275c208 100644
--- a/tests/src/com/android/telecomm/testcallservice/TestCallService.java
+++ b/tests/src/com/android/telecomm/testcallservice/TestCallService.java
@@ -20,6 +20,7 @@
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
import android.telecomm.CallAudioState;
import android.telecomm.CallInfo;
import android.telecomm.CallService;
@@ -31,35 +32,27 @@
import com.android.telecomm.tests.R;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
-import com.google.common.collect.Sets;
+import com.google.common.collect.Maps;
-import java.util.Set;
+import java.util.Map;
/**
* Service which provides fake calls to test the ICallService interface.
* TODO(santoscordon): Rename all classes in the directory to Dummy* (e.g., DummyCallService).
*/
public class TestCallService extends CallService {
- private static final String TAG = TestCallService.class.getSimpleName();
+ private static final String SCHEME_TEL = "tel";
- /**
- * Set of call IDs for live (active, ringing, dialing) calls.
- * TODO(santoscordon): Reference CallState javadoc when available for the different call states.
- */
- private Set<String> mLiveCallIds;
+ private final Map<String, CallInfo> mCalls = Maps.newHashMap();
+ private final Handler mHandler = new Handler();
- /**
- * Used to play an audio tone during a call.
- */
+ /** Used to play an audio tone during a call. */
private MediaPlayer mMediaPlayer;
/** {@inheritDoc} */
@Override
public void onAdapterAttached(CallServiceAdapter callServiceAdapter) {
- Log.i(TAG, "setCallServiceAdapter()");
-
- mLiveCallIds = Sets.newHashSet();
-
+ log("onAdapterAttached");
mMediaPlayer = createMediaPlayer();
}
@@ -71,75 +64,79 @@
*/
@Override
public void isCompatibleWith(CallInfo callInfo) {
- Log.i(TAG, "isCompatibleWith(" + callInfo + ")");
+ log("isCompatibleWith, callInfo: " + callInfo);
Preconditions.checkNotNull(callInfo.getHandle());
// Is compatible if the handle doesn't start with 7.
boolean isCompatible = !callInfo.getHandle().getSchemeSpecificPart().startsWith("7");
- // Tell CallsManager whether this call service can place the call (is compatible).
- // Returning positively on setCompatibleWith() doesn't guarantee that we will be chosen
- // to place the call. If we *are* chosen then CallsManager will execute the call()
- // method below.
+ // Tell CallsManager whether this call service can place the call.
getAdapter().setIsCompatibleWith(callInfo.getId(), isCompatible);
}
/**
- * Starts a call by calling into the adapter. For testing purposes this methods acts as if a
- * call was successfully connected every time.
+ * Starts a call by calling into the adapter.
*
* {@inheritDoc}
*/
@Override
- public void call(CallInfo callInfo) {
+ public void call(final CallInfo callInfo) {
String number = callInfo.getHandle().getSchemeSpecificPart();
- Log.i(TAG, "call(" + number + ")");
+ log("call, number: " + number);
// Crash on 555-DEAD to test call service crashing.
if ("5550340".equals(number)) {
throw new RuntimeException("Goodbye, cruel world.");
}
- createCall(callInfo.getId());
+ mCalls.put(callInfo.getId(), callInfo);
getAdapter().handleSuccessfulOutgoingCall(callInfo.getId());
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ activateCall(callInfo.getId());
+ }
+ }, 4000);
}
/** {@inheritDoc} */
@Override
public void abort(String callId) {
- Log.i(TAG, "abort(" + callId + ")");
+ log("abort, callId: " + callId);
destroyCall(callId);
}
/** {@inheritDoc} */
@Override
public void setIncomingCallId(String callId, Bundle extras) {
- Log.i(TAG, "setIncomingCallId(" + callId + ", " + extras + ")");
+ log("setIncomingCallId, callId: " + callId + " extras: " + extras);
// Use dummy number for testing incoming calls.
- Uri handle = Uri.fromParts("tel", "5551234", null);
+ Uri handle = Uri.fromParts(SCHEME_TEL, "5551234", null);
CallInfo callInfo = new CallInfo(callId, CallState.RINGING, handle);
+ mCalls.put(callInfo.getId(), callInfo);
getAdapter().notifyIncomingCall(callInfo);
}
/** {@inheritDoc} */
@Override
public void answer(String callId) {
- getAdapter().setActive(callId);
- createCall(callId);
+ log("answer, callId: " + callId);
+ activateCall(callId);
}
/** {@inheritDoc} */
@Override
public void reject(String callId) {
+ log("reject, callId: " + callId);
getAdapter().setDisconnected(callId, DisconnectCause.INCOMING_REJECTED, null);
}
/** {@inheritDoc} */
@Override
public void disconnect(String callId) {
- Log.i(TAG, "disconnect(" + callId + ")");
+ log("disconnect, callId: " + callId);
destroyCall(callId);
getAdapter().setDisconnected(callId, DisconnectCause.LOCAL, null);
@@ -148,55 +145,45 @@
/** {@inheritDoc} */
@Override
public void hold(String callId) {
- Log.i(TAG, "hold(" + callId + ")");
+ log("hold, callId: " + callId);
getAdapter().setOnHold(callId);
}
/** {@inheritDoc} */
@Override
public void unhold(String callId) {
- Log.i(TAG, "unhold(" + callId + ")");
+ log("unhold, callId: " + callId);
getAdapter().setActive(callId);
}
/** {@inheritDoc} */
@Override
public void playDtmfTone(String callId, char digit) {
- Log.i(TAG, "playDtmfTone(" + callId + "," + digit + ")");
- // TODO(ihab): Implement
+ log("playDtmfTone, callId: " + callId + " digit: " + digit);
}
/** {@inheritDoc} */
@Override
public void stopDtmfTone(String callId) {
- Log.i(TAG, "stopDtmfTone(" + callId + ")");
- // TODO(ihab): Implement
+ log("stopDtmfTone, callId: " + callId);
}
/** {@inheritDoc} */
@Override
public void onAudioStateChanged(String callId, CallAudioState audioState) {
+ log("onAudioStateChanged, callId: " + callId + " audioState: " + audioState);
}
/** {@inheritDoc} */
@Override
public boolean onUnbind(Intent intent) {
+ log("onUnbind");
mMediaPlayer = null;
-
return super.onUnbind(intent);
}
- /**
- * Adds the specified call ID to the set of live call IDs and starts playing audio on the
- * voice-call stream.
- *
- * @param callId The identifier of the call to create.
- */
- private void createCall(String callId) {
- Preconditions.checkState(!Strings.isNullOrEmpty(callId));
- mLiveCallIds.add(callId);
-
- // Starts audio if not already started.
+ private void activateCall(String callId) {
+ getAdapter().setActive(callId);
if (!mMediaPlayer.isPlaying()) {
mMediaPlayer.start();
}
@@ -210,10 +197,10 @@
*/
private void destroyCall(String callId) {
Preconditions.checkState(!Strings.isNullOrEmpty(callId));
- mLiveCallIds.remove(callId);
+ mCalls.remove(callId);
// Stops audio if there are no more calls.
- if (mLiveCallIds.isEmpty() && mMediaPlayer.isPlaying()) {
+ if (mCalls.isEmpty() && mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = createMediaPlayer();
@@ -227,4 +214,7 @@
return mediaPlayer;
}
+ private static void log(String msg) {
+ Log.w("testcallservice", "[TestCallService] " + msg);
+ }
}
diff --git a/tests/src/com/android/telecomm/testcallservice/TestCallServiceProvider.java b/tests/src/com/android/telecomm/testcallservice/TestCallServiceProvider.java
index 781f629..3a6646c 100644
--- a/tests/src/com/android/telecomm/testcallservice/TestCallServiceProvider.java
+++ b/tests/src/com/android/telecomm/testcallservice/TestCallServiceProvider.java
@@ -28,12 +28,10 @@
* TODO(santoscordon): Build more dummy providers for more CallServiceDescriptor.FLAG_* types.
*/
public class TestCallServiceProvider extends CallServiceProvider {
- private static final String TAG = TestCallServiceProvider.class.getSimpleName();
-
/** {@inheritDoc} */
@Override
public void lookupCallServices(CallServiceLookupResponse response) {
- Log.i(TAG, "lookupCallServices()");
+ log("lookupCallServices");
CallServiceDescriptor.Builder builder = CallServiceDescriptor.newBuilder(this);
builder.setCallService(TestCallService.class);
@@ -41,4 +39,8 @@
response.setCallServiceDescriptors(Lists.newArrayList(builder.build()));
}
+
+ private static void log(String msg) {
+ Log.w("testcallservice", "[TestCallServiceProvider] " + msg);
+ }
}