Make incoming calls work.
This is a CL of random changes. Ties of loose ends which were previously
commented and adds new wiring to connect all the pieces together.
After this CL, incoming calls are functional for call services.
Change-Id: I6fa1e70b816094587849329790236f9289ec260b
diff --git a/src/com/android/telecomm/Call.java b/src/com/android/telecomm/Call.java
index 4576075..7049742 100644
--- a/src/com/android/telecomm/Call.java
+++ b/src/com/android/telecomm/Call.java
@@ -64,6 +64,13 @@
private CallInfo mCallInfo;
/**
+ * Creates an empty call object with a unique call ID.
+ */
+ Call() {
+ this(null, null);
+ }
+
+ /**
* Persists the specified parameters and initializes the new instance.
*
* @param handle The handle to dial.
diff --git a/src/com/android/telecomm/CallActivity.java b/src/com/android/telecomm/CallActivity.java
index 7fc027f..1f9ffab 100644
--- a/src/com/android/telecomm/CallActivity.java
+++ b/src/com/android/telecomm/CallActivity.java
@@ -126,6 +126,7 @@
return;
}
- // Notify CallsManager.
+ Log.d(TAG, "Processing incoming call from call service [" + descriptor + "]");
+ mCallsManager.processIncomingCallIntent(descriptor);
}
}
diff --git a/src/com/android/telecomm/CallServiceAdapter.java b/src/com/android/telecomm/CallServiceAdapter.java
index 9e20d0c..17063c3 100644
--- a/src/com/android/telecomm/CallServiceAdapter.java
+++ b/src/com/android/telecomm/CallServiceAdapter.java
@@ -44,6 +44,8 @@
private final OutgoingCallsManager mOutgoingCallsManager;
+ private final IncomingCallsManager mIncomingCallsManager;
+
/** Used to run code (e.g. messages, Runnables) on the main (UI) thread. */
private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -55,10 +57,16 @@
/**
* Persists the specified parameters.
+ *
+ * @param outgoingCallsManager Manages the placing of outgoing calls.
+ * @param incomingCallsManager Manages the incoming call initialization flow.
*/
- CallServiceAdapter(OutgoingCallsManager outgoingCallsManager) {
+ CallServiceAdapter(
+ OutgoingCallsManager outgoingCallsManager, IncomingCallsManager incomingCallsManager) {
+
mCallsManager = CallsManager.getInstance();
mOutgoingCallsManager = outgoingCallsManager;
+ mIncomingCallsManager = incomingCallsManager;
}
/** {@inheritDoc} */
@@ -72,8 +80,7 @@
mHandler.post(new Runnable() {
@Override public void run() {
if (mPendingIncomingCallIds.remove(callInfo.getId())) {
- // TODO(santoscordon): Uncomment when ready.
- // mIncomingCallsManager.handleSuccessfulIncomingCall(callInfo);
+ mIncomingCallsManager.handleSuccessfulIncomingCall(callInfo);
} else {
Log.wtf(TAG, "Received details for an unknown incoming call " + callInfo);
}
diff --git a/src/com/android/telecomm/CallServiceRepository.java b/src/com/android/telecomm/CallServiceRepository.java
index dfedb57..5567e51 100644
--- a/src/com/android/telecomm/CallServiceRepository.java
+++ b/src/com/android/telecomm/CallServiceRepository.java
@@ -63,6 +63,8 @@
private final OutgoingCallsManager mOutgoingCallsManager;
+ private final IncomingCallsManager mIncomingCallsManager;
+
/** Used to run code (e.g. messages, Runnables) on the main (UI) thread. */
private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -111,11 +113,17 @@
* Persists the specified parameters.
*
* @param switchboard The switchboard.
- * @param outgoingCallsManager Manager in charge of placing outgoing calls.
+ * @param outgoingCallsManager Manages the placing of outgoing calls.
+ * @param incomingCallsManager Manages the incoming call initialization flow.
*/
- CallServiceRepository(Switchboard switchboard, OutgoingCallsManager outgoingCallsManager) {
+ CallServiceRepository(
+ Switchboard switchboard,
+ OutgoingCallsManager outgoingCallsManager,
+ IncomingCallsManager incomingCallsManager) {
+
mSwitchboard = switchboard;
mOutgoingCallsManager = outgoingCallsManager;
+ mIncomingCallsManager = incomingCallsManager;
}
/**
@@ -311,7 +319,8 @@
CallServiceWrapper callService = mCallServices.get(callServiceName);
if (callService == null) {
- CallServiceAdapter adapter = new CallServiceAdapter(mOutgoingCallsManager);
+ CallServiceAdapter adapter =
+ new CallServiceAdapter(mOutgoingCallsManager, mIncomingCallsManager);
mCallServices.put(callServiceName, new CallServiceWrapper(descriptor, adapter));
}
}
diff --git a/src/com/android/telecomm/CallServiceWrapper.java b/src/com/android/telecomm/CallServiceWrapper.java
index 5d2162a..bb9d649 100644
--- a/src/com/android/telecomm/CallServiceWrapper.java
+++ b/src/com/android/telecomm/CallServiceWrapper.java
@@ -24,6 +24,8 @@
import android.telecomm.ICallServiceAdapter;
import android.util.Log;
+import com.android.telecomm.ServiceBinder.BindCallback;
+
/**
* Wrapper for {@link ICallService}s, handles binding to {@link ICallService} and keeps track of
* when the object can safely be unbound. Other classes should not use {@link ICallService} directly
@@ -149,6 +151,27 @@
}
/**
+ * Starts retrieval of details for an incoming call. Details are returned through the
+ * call-service adapter using the specified call ID. Upon failure, the specified error callback
+ * is invoked. Can be invoked even when the call service is unbound.
+ *
+ * @param callID The call ID used for the incoming call.
+ * @param errorCallback The callback invoked upon failure.
+ */
+ void retrieveIncomingCall(final String callId, final Runnable errorCallback) {
+ BindCallback callback = new BindCallback() {
+ @Override public void onSuccess() {
+ setIncomingCallId(callId);
+ }
+ @Override public void onFailure() {
+ errorCallback.run();
+ }
+ };
+
+ bind(callback);
+ }
+
+ /**
* Cancels the incoming call for the specified call ID.
* TODO(santoscordon): This method should be called by IncomingCallsManager when the incoming
* call has failed.
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index 9922102..c049e18 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -84,21 +84,20 @@
}
/**
- * Starts the incoming call sequence by having switchboard confirm with the specified call
- * service that an incoming call actually exists for the specified call token. Upon success,
- * execution returns to {@link #handleSuccessfulIncomingCall} to start the in-call UI.
+ * Starts the incoming call sequence by having switchboard gather more information about the
+ * specified call; using the specified call service descriptor. Upon success, execution returns
+ * to {@link #handleSuccessfulIncomingCall} to start the in-call UI.
*
* @param descriptor The descriptor of the call service to use for this incoming call.
- * @param callToken The token used by the call service to identify the incoming call.
*/
- void processIncomingCallIntent(CallServiceDescriptor descriptor, String callToken) {
+ void processIncomingCallIntent(CallServiceDescriptor descriptor) {
Log.d(TAG, "processIncomingCallIntent");
// Create a call with no handle. Eventually, switchboard will update the call with
// additional information from the call service, but for now we just need one to pass around
// with a unique call ID.
- Call call = new Call(null, null);
+ Call call = new Call();
- mSwitchboard.confirmIncomingCall(call, descriptor, callToken);
+ mSwitchboard.retrieveIncomingCall(call, descriptor);
}
/**
diff --git a/src/com/android/telecomm/IncomingCallsManager.java b/src/com/android/telecomm/IncomingCallsManager.java
index 063469d..1539cbf 100644
--- a/src/com/android/telecomm/IncomingCallsManager.java
+++ b/src/com/android/telecomm/IncomingCallsManager.java
@@ -18,24 +18,26 @@
import android.os.Handler;
import android.os.Looper;
+import android.telecomm.CallInfo;
+import android.util.Log;
-import com.android.telecomm.ServiceBinder.BindCallback;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import java.util.Map;
/**
- * Utility class to confirm the existence of an incoming call after receiving an incoming-call
- * intent, see {@link TelecommReceiver}. Binds with the specified call services and requests
- * confirmation of incoming calls using call tokens provided as part of the intent. Upon receipt of
- * the confirmation, yields execution back to the switchboard to complete the incoming sequence. The
- * entire process is timeboxed to protect against unresponsive call services.
+ * Utility class to retrieve details of an incoming call after receiving an incoming-call intent,
+ * see {@link CallActivity}. Binds with the specified call services and requests details of incoming
+ * calls. Upon receipt of the details, yields execution back to the switchboard to complete the
+ * incoming sequence. The entire process is timeboxed to protect against unresponsive call services.
*/
final class IncomingCallsManager {
+ private static final String TAG = IncomingCallsManager.class.getSimpleName();
+
/**
- * The amount of time to wait for confirmation of an incoming call, in milliseconds.
+ * The amount of time to wait for details of an incoming call, in milliseconds.
* TODO(santoscordon): Likely needs adjustment.
*/
private static final int INCOMING_CALL_TIMEOUT_MS = 1000;
@@ -44,8 +46,8 @@
private final Handler mHandler = new Handler(Looper.getMainLooper());
- /** Maps incoming calls to their call services. */
- private final Map<Call, CallServiceWrapper> mPendingIncomingCalls = Maps.newHashMap();
+ /** Maps call ID to the call. */
+ private final Map<String, Call> mPendingIncomingCalls = Maps.newHashMap();
/**
* Persists the specified parameters.
@@ -57,63 +59,44 @@
}
/**
- * Confirms the existence of an incoming call with the specified call service (asynchronously).
+ * Retrieves details of an incoming call through its associated call service (asynchronously).
* Starts the timeout sequence in case the call service is unresponsive.
*
* @param call The call object.
- * @param callService The call service.
- * @param callToken The token used by the call service to identify the incoming call.
*/
- void confirmIncomingCall(
- final Call call, final CallServiceWrapper callService, String callToken) {
-
+ void retrieveIncomingCall(Call call) {
ThreadUtil.checkOnMainThread();
- // Just to be safe, lets make sure we're not already processing this call.
- Preconditions.checkState(!mPendingIncomingCalls.containsKey(call));
+ Log.d(TAG, "retrieveIncomingCall");
- mPendingIncomingCalls.put(call, callService);
+ final String callId = call.getId();
+ // Just to be safe, lets make sure we're not already processing this call.
+ Preconditions.checkState(!mPendingIncomingCalls.containsKey(callId));
+
+ mPendingIncomingCalls.put(callId, call);
+
+ // TODO(santoscordon): Timeout will not be necessary after cleanup via tick() is implemented
+ // in Switchboard.
startTimeoutForCall(call);
- BindCallback callback = new BindCallback() {
- @Override public void onSuccess() {
- // TODO(santoscordon): ICallService needs to be updated with the following method.
- // Confirmation won't work until this method is filled in.
- // callService.confirmIncomingCall(call.toCallInfo(), callToken);
- }
- @Override public void onFailure() {
- handleFailedIncomingCall(call);
- }
- };
-
- callService.bind(callback);
- }
-
- /**
- * Starts a timeout to timebox the confirmation of an incoming call. When the timeout expires,
- * it will notify switchboard that the incoming call was not confirmed and thus does not exist
- * as far as Telecomm is concerned.
- *
- * @param call The call.
- */
- void startTimeoutForCall(final Call call) {
- Runnable timeoutCallback = new Runnable() {
- @Override public void run() {
- handleFailedIncomingCall(call);
- }
- };
- mHandler.postDelayed(timeoutCallback, INCOMING_CALL_TIMEOUT_MS);
+ Runnable errorCallback = getFailedIncomingCallback(call);
+ call.getCallService().retrieveIncomingCall(callId, errorCallback);
}
/**
* Notifies the switchboard of a successful incoming call after removing it from the pending
* list.
- * TODO(santoscordon): Needs code in CallServiceAdapter to call this method.
*
- * @param call The call.
+ * @param callInfo The details of the call.
*/
- void handleSuccessfulIncomingCall(Call call) {
+ void handleSuccessfulIncomingCall(CallInfo callInfo) {
ThreadUtil.checkOnMainThread();
- if (mPendingIncomingCalls.remove(call) != null) {
+
+ Call call = mPendingIncomingCalls.remove(callInfo.getId());
+ if (call != null) {
+ Log.d(TAG, "Incoming call " + call.getId() + " found.");
+ call.setHandle(callInfo.getHandle());
+ call.setState(callInfo.getState());
+
mSwitchboard.handleSuccessfulIncomingCall(call);
}
}
@@ -123,11 +106,38 @@
*
* @param call The call.
*/
- void handleFailedIncomingCall(Call call) {
+ private void handleFailedIncomingCall(Call call) {
ThreadUtil.checkOnMainThread();
- if (mPendingIncomingCalls.remove(call) != null) {
- // The call was found still waiting for confirmation. Consider it failed.
+
+ if (mPendingIncomingCalls.remove(call.getId()) != null) {
+ Log.i(TAG, "Failed to get details for incoming call " + call);
+ // The call was found still waiting for details. Consider it failed.
mSwitchboard.handleFailedIncomingCall(call);
}
}
+
+ /**
+ * Starts a timeout to timebox the retrieval of an incoming call. When the timeout expires,
+ * it will notify switchboard that the incoming call was not retrieved and thus does not exist
+ * as far as Telecomm is concerned.
+ *
+ * @param call The call.
+ */
+ private void startTimeoutForCall(Call call) {
+ Runnable timeoutCallback = getFailedIncomingCallback(call);
+ mHandler.postDelayed(timeoutCallback, INCOMING_CALL_TIMEOUT_MS);
+ }
+
+ /**
+ * Returns a runnable to be invoked upon failure to get details for an incoming call.
+ *
+ * @param call The failed incoming call.
+ */
+ private Runnable getFailedIncomingCallback(final Call call) {
+ return new Runnable() {
+ @Override public void run() {
+ handleFailedIncomingCall(call);
+ }
+ };
+ }
}
diff --git a/src/com/android/telecomm/OutgoingCallProcessor.java b/src/com/android/telecomm/OutgoingCallProcessor.java
index a78f951..99c0274 100644
--- a/src/com/android/telecomm/OutgoingCallProcessor.java
+++ b/src/com/android/telecomm/OutgoingCallProcessor.java
@@ -268,6 +268,8 @@
attemptNextCallService();
}
};
+ // TODO(santoscordon): Consider making bind private to CallServiceWrapper and having
+ // CSWrapper.call() do the bind automatically.
mCallService.bind(callback);
}
} else {
diff --git a/src/com/android/telecomm/ServiceBinder.java b/src/com/android/telecomm/ServiceBinder.java
index 9619239..3c84967 100644
--- a/src/com/android/telecomm/ServiceBinder.java
+++ b/src/com/android/telecomm/ServiceBinder.java
@@ -22,6 +22,7 @@
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.IInterface;
+import android.util.Log;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
@@ -72,6 +73,8 @@
}
}
+ private static final String TAG = ServiceBinder.class.getSimpleName();
+
/** The application context. */
private final Context mContext;
@@ -119,6 +122,7 @@
*/
final boolean bind(BindCallback callback) {
ThreadUtil.checkOnMainThread();
+ Log.d(TAG, "bind()");
// Reset any abort request if we're asked to bind again.
clearAbort();
@@ -135,11 +139,13 @@
Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
ServiceConnection connection = new ServiceBinderConnection();
+ Log.d(TAG, "Binding to call service with intent: " + serviceIntent);
if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
handleFailedConnection();
return false;
}
} else {
+ Log.d(TAG, "Service is already bound.");
Preconditions.checkNotNull(mBinder);
handleSuccessfulConnection();
}
diff --git a/src/com/android/telecomm/Switchboard.java b/src/com/android/telecomm/Switchboard.java
index 5283e0b..8661e51 100644
--- a/src/com/android/telecomm/Switchboard.java
+++ b/src/com/android/telecomm/Switchboard.java
@@ -24,6 +24,7 @@
import android.os.Looper;
import android.telecomm.CallServiceDescriptor;
import android.telecomm.ICallServiceSelector;
+import android.util.Log;
import java.util.Collection;
import java.util.List;
@@ -36,6 +37,7 @@
*/
final class Switchboard {
+ private final static String TAG = Switchboard.class.getSimpleName();
/**
* The frequency of invoking tick in milliseconds.
* TODO(gilad): May require tuning.
@@ -47,7 +49,7 @@
/** Used to place outgoing calls. */
private final OutgoingCallsManager mOutgoingCallsManager;
- /** Used to confirm incoming calls. */
+ /** Used to retrieve incoming call details. */
private final IncomingCallsManager mIncomingCallsManager;
private final CallServiceRepository mCallServiceRepository;
@@ -103,8 +105,9 @@
mCallsManager = callsManager;
mOutgoingCallsManager = new OutgoingCallsManager(this);
mIncomingCallsManager = new IncomingCallsManager(this);
- mCallServiceRepository = new CallServiceRepository(this, mOutgoingCallsManager);
mSelectorRepository = new CallServiceSelectorRepository(this);
+ mCallServiceRepository =
+ new CallServiceRepository(this, mOutgoingCallsManager, mIncomingCallsManager);
}
/**
@@ -135,18 +138,18 @@
}
/**
- * Confirms with incoming call manager that an incoming call exists for the specified call
- * service and call token. The incoming call manager will invoke either
- * {@link #handleSuccessfulIncomingCall} or {@link #handleFailedIncomingCall} depending
- * on the result.
+ * Retrieves details about the incoming call through the incoming call manager. The incoming
+ * call manager will invoke either {@link #handleSuccessfulIncomingCall} or
+ * {@link #handleFailedIncomingCall} depending on the result of the retrieval.
*
* @param call The call object.
* @param descriptor The relevant call-service descriptor.
- * @param callToken The token used by the call service to identify the incoming call.
*/
- void confirmIncomingCall(Call call, CallServiceDescriptor descriptor, String callToken) {
+ void retrieveIncomingCall(Call call, CallServiceDescriptor descriptor) {
+ Log.d(TAG, "retrieveIncomingCall");
CallServiceWrapper callService = mCallServiceRepository.getCallService(descriptor);
- mIncomingCallsManager.confirmIncomingCall(call, callService, callToken);
+ call.setCallService(callService);
+ mIncomingCallsManager.retrieveIncomingCall(call);
}
/**
@@ -208,26 +211,30 @@
}
/**
- * Handles the case where we received confirmation of an incoming call. Hands the resulting
- * call to {@link CallsManager} as the final step in the incoming sequence. At that point,
- * {@link CallsManager} should bring up the incoming-call UI.
+ * Handles the case where we successfully receive details of an incoming call. Hands the
+ * resulting call to {@link CallsManager} as the final step in the incoming sequence. At that
+ * point, {@link CallsManager} should bring up the incoming-call UI.
*/
void handleSuccessfulIncomingCall(Call call) {
+ Log.d(TAG, "handleSuccessfulIncomingCall");
mCallsManager.handleSuccessfulIncomingCall(call);
}
/**
- * Handles the case where we failed to confirm an incoming call after receiving an incoming-call
- * intent via {@link TelecommReceiver}.
+ * Handles the case where we failed to retrieve an incoming call after receiving an incoming-call
+ * intent via {@link CallActivity}.
*
* @param call The call.
*/
void handleFailedIncomingCall(Call call) {
- // At the moment there is nothing to do if an incoming call is not confirmed. We may at a
- // future date bind to the in-call app optimistically during the incoming-call sequence and
- // this method could tell {@link CallsManager} to unbind from the in-call app if the
- // incoming call was not confirmed. It's worth keeping this method for parity with the
- // outgoing call sequence.
+ // Since we set the call service before calling into incoming-calls manager, we clear it for
+ // good measure if an error is reported.
+ call.clearCallService();
+
+ // At the moment there is nothing more to do if an incoming call is not retrieved. We may at
+ // a future date bind to the in-call app optimistically during the incoming-call sequence
+ // and this method could tell {@link CallsManager} to unbind from the in-call app if the
+ // incoming call was not retrieved.
}
/**