Work in preparation for wiring up the remaining de-allocation and
abort bits.
1) limit to one attempt per call service upon multiple selectors
returning the same call service
2) record the failing/incompatible ones such that these are avoided
when switching
3) addressing some related todos etc.
Change-Id: I62204e9947bb8557888df33ca70f4352d3e6decf
diff --git a/src/com/android/telecomm/Call.java b/src/com/android/telecomm/Call.java
index d54072d..6660dc3 100644
--- a/src/com/android/telecomm/Call.java
+++ b/src/com/android/telecomm/Call.java
@@ -20,10 +20,12 @@
import android.telecomm.CallState;
import com.android.internal.telecomm.ICallServiceSelector;
+import com.google.android.collect.Sets;
import com.google.common.base.Preconditions;
import java.util.Date;
import java.util.Locale;
+import java.util.Set;
import java.util.UUID;
/**
@@ -67,6 +69,12 @@
private CallInfo mCallInfo;
/**
+ * The set of call services that were attempted in the process of placing/switching this call
+ * but turned out unsuitable. Only used in the context of call switching.
+ */
+ private Set<CallServiceWrapper> mIncompatibleCallServices;
+
+ /**
* Creates an empty call object with a unique call ID.
*/
Call() {
@@ -177,6 +185,32 @@
}
/**
+ * Adds the specified call service to the list of incompatible services. The set is used when
+ * attempting to switch a phone call between call services such that incompatible services can
+ * be avoided.
+ *
+ * @param callService The incompatible call service.
+ */
+ void addIncompatibleCallService(CallServiceWrapper callService) {
+ if (mIncompatibleCallServices == null) {
+ mIncompatibleCallServices = Sets.newHashSet();
+ }
+ mIncompatibleCallServices.add(callService);
+ }
+
+ /**
+ * Checks whether or not the specified callService was identified as incompatible in the
+ * context of this call.
+ *
+ * @param callService The call service to evaluate.
+ * @return True upon incompatible call services and false otherwise.
+ */
+ boolean isIncompatibleCallService(CallServiceWrapper callService) {
+ return mIncompatibleCallServices != null &&
+ mIncompatibleCallServices.contains(callService);
+ }
+
+ /**
* Aborts ongoing attempts to connect this call. Only applicable to {@link CallState#NEW}
* outgoing calls. See {@link #disconnect} for already-connected calls.
*/
diff --git a/src/com/android/telecomm/CallServiceAdapter.java b/src/com/android/telecomm/CallServiceAdapter.java
index 3e63f39..1e830d5 100644
--- a/src/com/android/telecomm/CallServiceAdapter.java
+++ b/src/com/android/telecomm/CallServiceAdapter.java
@@ -74,8 +74,17 @@
}
/** {@inheritDoc} */
- @Override public void setIsCompatibleWith(String callId, boolean isCompatible) {
- // TODO(santoscordon): fill in.
+ @Override public void setIsCompatibleWith(final String callId, final boolean isCompatible) {
+ checkValidCallId(callId);
+ mHandler.post(new Runnable() {
+ @Override public void run() {
+ if (mPendingOutgoingCallIds.contains(callId)) {
+ mOutgoingCallsManager.setIsCompatibleWith(callId, isCompatible);
+ } else {
+ Log.wtf(CallServiceAdapter.this, "Unknown outgoing call: %s", callId);
+ }
+ }
+ });
}
/** {@inheritDoc} */
@@ -86,8 +95,7 @@
if (mPendingIncomingCallIds.remove(callInfo.getId())) {
mIncomingCallsManager.handleSuccessfulIncomingCall(callInfo);
} else {
- Log.wtf(CallServiceAdapter.this,
- "Unknown incoming call: %s", callInfo);
+ Log.wtf(CallServiceAdapter.this, "Unknown incoming call: %s", callInfo);
}
}
});
@@ -102,8 +110,7 @@
mOutgoingCallsManager.handleSuccessfulCallAttempt(callId);
} else {
// TODO(gilad): Figure out how to wire up the callService.abort() call.
- Log.wtf(CallServiceAdapter.this,
- "Unknown outgoing call: %s", callId);
+ Log.wtf(CallServiceAdapter.this, "Unknown outgoing call: %s", callId);
}
}
});
@@ -117,8 +124,7 @@
if (mPendingOutgoingCallIds.remove(callId)) {
mOutgoingCallsManager.handleFailedCallAttempt(callId, reason);
} else {
- Log.wtf(CallServiceAdapter.this,
- "Unknown outgoing call: %s", callId);
+ Log.wtf(CallServiceAdapter.this, "Unknown outgoing call: %s", callId);
}
}
});
diff --git a/src/com/android/telecomm/CallServiceProviderWrapper.java b/src/com/android/telecomm/CallServiceProviderWrapper.java
index 97303cd..1a3b3e1 100644
--- a/src/com/android/telecomm/CallServiceProviderWrapper.java
+++ b/src/com/android/telecomm/CallServiceProviderWrapper.java
@@ -31,35 +31,56 @@
* {@link ICallServiceProvider}.
* TODO(santoscordon): Keep track of when the service can be safely unbound.
*/
-public class CallServiceProviderWrapper extends ServiceBinder<ICallServiceProvider> {
+final class CallServiceProviderWrapper extends ServiceBinder<ICallServiceProvider> {
+ /**
+ * The service action used to bind to ICallServiceProvider implementations.
+ * TODO(santoscordon): Move this to TelecommConstants.
+ */
+ static final String CALL_SERVICE_PROVIDER_ACTION = ICallServiceProvider.class.getName();
+
/** The actual service implementation. */
private ICallServiceProvider mServiceInterface;
+ private Binder mBinder = new Binder();
+
/**
* Creates a call-service provider for the specified component.
*
* @param componentName The component name of the service to bind to.
- * @param repository The call-service repository.
*/
- public CallServiceProviderWrapper(
- ComponentName componentName, CallServiceRepository repository) {
-
+ CallServiceProviderWrapper(ComponentName componentName) {
super(TelecommConstants.ACTION_CALL_SERVICE_PROVIDER, componentName);
}
/**
- * See {@link ICallServiceProvider#lookupCallServices}.
+ * initiates a call-service lookup cycle, see {@link ICallServiceProvider#lookupCallServices}.
+ * Upon failure, the specified error callback is invoked. Can be invoked even when the call
+ * service is unbound.
+ *
+ * @param response The response object via which to return the relevant call-service
+ * implementations, if any.
+ * @param errorCallback The callback to invoke upon failure.
*/
- public void lookupCallServices(ICallServiceLookupResponse response) {
- try {
- if (mServiceInterface == null) {
- Log.wtf(this, "lookupCallServices() invoked while the service is unbound.");
- } else {
- mServiceInterface.lookupCallServices(response);
+ void lookupCallServices(
+ final ICallServiceLookupResponse response,
+ final Runnable errorCallback) {
+
+ BindCallback callback = new BindCallback() {
+ @Override public void onSuccess() {
+ if (isServiceValid("lookupCallServices")) {
+ try {
+ mServiceInterface.lookupCallServices(response);
+ } catch (RemoteException e) {
+ Log.e(CallServiceProviderWrapper.this, e, "Failed to lookupCallServices.");
+ }
+ }
}
- } catch (RemoteException e) {
- Log.e(this, e, "Failed to lookupCallServices.");
- }
+ @Override public void onFailure() {
+ errorCallback.run();
+ }
+ };
+
+ mBinder.bind(callback);
}
/** {@inheritDoc} */
diff --git a/src/com/android/telecomm/CallServiceRepository.java b/src/com/android/telecomm/CallServiceRepository.java
index 6a341cd..2abc8fe 100644
--- a/src/com/android/telecomm/CallServiceRepository.java
+++ b/src/com/android/telecomm/CallServiceRepository.java
@@ -28,7 +28,6 @@
import com.android.internal.telecomm.ICallServiceLookupResponse;
import com.android.internal.telecomm.ICallServiceProvider;
-import com.android.telecomm.ServiceBinder.BindCallback;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -143,7 +142,7 @@
mOutstandingProviders.clear();
for (ComponentName name : providerNames) {
mOutstandingProviders.add(name);
- bindProvider(name);
+ lookupCallServices(name);
}
Log.i(this, "Found %d implementations of ICallServiceProvider.",
@@ -213,41 +212,16 @@
}
/**
- * Attempts to bind to the specified provider.
+ * Attempts to obtain call-service descriptors from the specified provider (asynchronously) and
+ * passes the list through to {@link #processCallServices}, which then relinquishes control back
+ * to the switchboard.
*
* @param providerName The component name of the relevant provider.
*/
- private void bindProvider(final ComponentName providerName) {
- final CallServiceProviderWrapper provider =
- new CallServiceProviderWrapper(providerName, this);
+ private void lookupCallServices(final ComponentName providerName) {
+ final CallServiceProviderWrapper provider = new CallServiceProviderWrapper(providerName);
- BindCallback callback = new BindCallback() {
- @Override public void onSuccess() {
- processProvider(provider);
- }
- @Override public void onFailure() {
- removeOutstandingProvider(providerName);
- }
- };
-
- provider.bind(callback);
- }
-
- /**
- * Queries the supplied provider asynchronously for its CallServices and passes the list through
- * to {@link #processCallServices} which will relinquish control back to switchboard.
- *
- * @param provider The provider object to process.
- */
- private void processProvider(final CallServiceProviderWrapper provider) {
- if (!mIsLookupInProgress) {
- return;
- }
-
- Preconditions.checkNotNull(provider);
-
- // Query the provider for {@link ICallService} implementations.
- provider.lookupCallServices(new ICallServiceLookupResponse.Stub() {
+ ICallServiceLookupResponse response = new ICallServiceLookupResponse.Stub() {
@Override
public void setCallServiceDescriptors(
final List<CallServiceDescriptor> callServiceDescriptors) {
@@ -255,11 +229,21 @@
// TODO(santoscordon): Do we need Binder.clear/restoreCallingIdentity()?
mHandler.post(new Runnable() {
@Override public void run() {
- processCallServices(provider, Sets.newHashSet(callServiceDescriptors));
+ if (mIsLookupInProgress) {
+ processCallServices(provider, Sets.newHashSet(callServiceDescriptors));
+ }
}
});
}
- });
+ };
+
+ Runnable errorCallback = new Runnable() {
+ @Override public void run() {
+ removeOutstandingProvider(providerName);
+ }
+ };
+
+ provider.lookupCallServices(response, errorCallback);
}
/**
@@ -291,8 +275,8 @@
removeOutstandingProvider(providerName);
} else {
- Log.i(this, "Unexpected list of call services in lookup %s from %s ", mLookupId,
- providerName);
+ Log.i(this,
+ "Unexpected call services from %s in lookup %s", providerName, mLookupId);
}
}
diff --git a/src/com/android/telecomm/CallServiceWrapper.java b/src/com/android/telecomm/CallServiceWrapper.java
index 5c9905e..c4d033c 100644
--- a/src/com/android/telecomm/CallServiceWrapper.java
+++ b/src/com/android/telecomm/CallServiceWrapper.java
@@ -35,7 +35,7 @@
* TODO(santoscordon): Keep track of when the service can be safely unbound.
* TODO(santoscordon): Look into combining with android.telecomm.CallService.
*/
-public class CallServiceWrapper extends ServiceBinder<ICallService> {
+final class CallServiceWrapper extends ServiceBinder<ICallService> {
/** The descriptor of this call service as supplied by the call-service provider. */
private final CallServiceDescriptor mDescriptor;
@@ -48,6 +48,8 @@
/** The actual service implementation. */
private ICallService mServiceInterface;
+ private Binder mBinder = new Binder();
+
/**
* Creates a call-service provider for the specified component.
*
@@ -55,18 +57,18 @@
* {@link ICallServiceProvider#lookupCallServices}.
* @param adapter The call-service adapter.
*/
- public CallServiceWrapper(CallServiceDescriptor descriptor, CallServiceAdapter adapter) {
+ CallServiceWrapper(CallServiceDescriptor descriptor, CallServiceAdapter adapter) {
super(TelecommConstants.ACTION_CALL_SERVICE, descriptor.getServiceComponent());
mDescriptor = descriptor;
mAdapter = adapter;
}
- public CallServiceDescriptor getDescriptor() {
+ CallServiceDescriptor getDescriptor() {
return mDescriptor;
}
/** See {@link ICallService#setCallServiceAdapter}. */
- public void setCallServiceAdapter(ICallServiceAdapter callServiceAdapter) {
+ void setCallServiceAdapter(ICallServiceAdapter callServiceAdapter) {
if (isServiceValid("setCallServiceAdapter")) {
try {
mServiceInterface.setCallServiceAdapter(callServiceAdapter);
@@ -76,32 +78,63 @@
}
}
- /** See {@link ICallService#isCompatibleWith}. */
- public void isCompatibleWith(CallInfo callInfo) {
- if (isServiceValid("isCompatibleWith")) {
- try {
- mServiceInterface.isCompatibleWith(callInfo);
- } catch (RemoteException e) {
- Log.e(this, e, "Failed checking isCompatibleWith.");
+ /**
+ * Checks whether or not the specified call is compatible with this call-service implementation,
+ * see {@link ICallService#isCompatibleWith}. Upon failure, the specified error callback is
+ * invoked. Can be invoked even when the call service is unbound.
+ *
+ * @param callInfo The details of the call.
+ * @param errorCallback The callback to invoke upon failure.
+ */
+ void isCompatibleWith(final CallInfo callInfo, final Runnable errorCallback) {
+ BindCallback callback = new BindCallback() {
+ @Override public void onSuccess() {
+ if (isServiceValid("isCompatibleWith")) {
+ try {
+ mServiceInterface.isCompatibleWith(callInfo);
+ } catch (RemoteException e) {
+ Log.e(CallServiceWrapper.this, e, "Failed checking isCompatibleWith.");
+ }
+ }
}
- }
+ @Override public void onFailure() {
+ errorCallback.run();
+ }
+ };
+
+ mBinder.bind(callback);
}
- /** See {@link ICallService#call}. */
- public void call(CallInfo callInfo) {
- String callId = callInfo.getId();
- if (isServiceValid("call")) {
- try {
- mServiceInterface.call(callInfo);
- mAdapter.addPendingOutgoingCallId(callId);
- } catch (RemoteException e) {
- Log.e(this, e, "Failed to place call " + callId + ".");
+ /**
+ * Attempts to place the specified call, see {@link ICallService#call}. Upon failure, the
+ * specified error callback is invoked. Can be invoked even when the call service is unbound.
+ *
+ * @param callInfo The details of the call.
+ * @param errorCallback The callback to invoke upon failure.
+ */
+ void call(final CallInfo callInfo, final Runnable errorCallback) {
+ BindCallback callback = new BindCallback() {
+ @Override public void onSuccess() {
+ String callId = callInfo.getId();
+ if (isServiceValid("call")) {
+ try {
+ mServiceInterface.call(callInfo);
+ mAdapter.addPendingOutgoingCallId(callId);
+ } catch (RemoteException e) {
+ Log.e(CallServiceWrapper.this, e, "Failed to place call %s", callId);
+ }
+ }
}
- }
+ @Override public void onFailure() {
+ errorCallback.run();
+ }
+ };
+
+ mBinder.bind(callback);
}
/** See {@link ICallService#abort}. */
- public void abort(String callId) {
+ void abort(String callId) {
mAdapter.removePendingOutgoingCallId(callId);
if (isServiceValid("abort")) {
try {
@@ -112,21 +145,44 @@
}
}
- /** See {@link ICallService#setIncomingCallId}. */
- public void setIncomingCallId(String callId, Bundle extras) {
- if (isServiceValid("setIncomingCallId")) {
- mAdapter.addPendingIncomingCallId(callId);
- try {
- mServiceInterface.setIncomingCallId(callId, extras);
- } catch (RemoteException e) {
- Log.e(this, e, "Failed to setIncomingCallId for call %s", callId);
- mAdapter.removePendingIncomingCallId(callId);
+ /**
+ * 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.
+ * See {@link ICallService#setIncomingCallId}.
+ *
+ * @param callId The call ID used for the incoming call.
+ * @param extras The {@link CallService}-provided extras which need to be sent back.
+ * @param errorCallback The callback to invoke upon failure.
+ */
+ void setIncomingCallId(
+ final String callId,
+ final Bundle extras,
+ final Runnable errorCallback) {
+
+ BindCallback callback = new BindCallback() {
+ @Override public void onSuccess() {
+ if (isServiceValid("setIncomingCallId")) {
+ mAdapter.addPendingIncomingCallId(callId);
+ try {
+ mServiceInterface.setIncomingCallId(callId, extras);
+ } catch (RemoteException e) {
+ Log.e(CallServiceWrapper.this, e,
+ "Failed to setIncomingCallId for call %s", callId);
+ mAdapter.removePendingIncomingCallId(callId);
+ }
+ }
}
- }
+ @Override public void onFailure() {
+ errorCallback.run();
+ }
+ };
+
+ mBinder.bind(callback);
}
/** See {@link ICallService#disconnect}. */
- public void disconnect(String callId) {
+ void disconnect(String callId) {
if (isServiceValid("disconnect")) {
try {
mServiceInterface.disconnect(callId);
@@ -137,7 +193,7 @@
}
/** See {@link ICallService#answer}. */
- public void answer(String callId) {
+ void answer(String callId) {
if (isServiceValid("answer")) {
try {
mServiceInterface.answer(callId);
@@ -148,7 +204,7 @@
}
/** See {@link ICallService#reject}. */
- public void reject(String callId) {
+ void reject(String callId) {
if (isServiceValid("reject")) {
try {
mServiceInterface.reject(callId);
@@ -159,30 +215,6 @@
}
/**
- * 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 extras The {@link CallService}-provided extras which need to be sent back.
- * @param errorCallback The callback invoked upon failure.
- */
- void retrieveIncomingCall(final String callId, final Bundle extras,
- final Runnable errorCallback) {
-
- BindCallback callback = new BindCallback() {
- @Override public void onSuccess() {
- setIncomingCallId(callId, extras);
- }
- @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.
@@ -198,13 +230,4 @@
mServiceInterface = ICallService.Stub.asInterface(binder);
setCallServiceAdapter(mAdapter);
}
-
- private boolean isServiceValid(String actionName) {
- if (mServiceInterface != null) {
- return true;
- }
-
- Log.wtf(this, "%s invoked while service is unbound", actionName);
- return false;
- }
}
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index 61f331b..cb9cab4 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -436,9 +436,9 @@
/**
* Stops playing the ringer if the specified call is the top-most incoming call. This exists
- * separately from {@link #removeIncomingCall} for cases where we would like to stop playing the
- * ringer for a call, but that call may still exist in {@link #mUnansweredIncomingCalls} - See
- * {@link #rejectCall}, {@link #answerCall}.
+ * separately from {@link #removeFromUnansweredCalls} to allow stopping the ringer for calls
+ * that should remain in {@link #mUnansweredIncomingCalls}, invoked from {@link #answerCall}
+ * and {@link #rejectCall}.
*
* @param call The call for which we should stop ringing.
*/
diff --git a/src/com/android/telecomm/IncomingCallsManager.java b/src/com/android/telecomm/IncomingCallsManager.java
index 7d33d6b..3b6365f 100644
--- a/src/com/android/telecomm/IncomingCallsManager.java
+++ b/src/com/android/telecomm/IncomingCallsManager.java
@@ -71,8 +71,7 @@
}
};
- // TODO(gilad): call.retrieve*Call() seems a bit unusual, consider revisiting.
- call.getCallService().retrieveIncomingCall(callId, extras, errorCallback);
+ call.getCallService().setIncomingCallId(callId, extras, errorCallback);
}
/**
diff --git a/src/com/android/telecomm/OutgoingCallProcessor.java b/src/com/android/telecomm/OutgoingCallProcessor.java
index bcfda61..a242866 100644
--- a/src/com/android/telecomm/OutgoingCallProcessor.java
+++ b/src/com/android/telecomm/OutgoingCallProcessor.java
@@ -16,10 +16,6 @@
package com.android.telecomm;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Lists;
-
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
@@ -28,7 +24,9 @@
import com.android.internal.telecomm.ICallServiceSelectionResponse;
import com.android.internal.telecomm.ICallServiceSelector;
-import com.android.telecomm.ServiceBinder.BindCallback;
+import com.google.android.collect.Sets;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Lists;
import java.util.Iterator;
import java.util.List;
@@ -68,6 +66,17 @@
private final Map<String, CallServiceWrapper> mCallServicesById = Maps.newHashMap();
/**
+ * The set of attempted call services, used to ensure services are attempted at most once per
+ * outgoing-call attempt.
+ */
+ private final Set<CallServiceWrapper> mAttemptedCallServices = Sets.newHashSet();
+
+ /**
+ * The set of incompatible call services, used to suppress unnecessary call switching attempts.
+ */
+ private final Set<CallServiceWrapper> mIncompatibleCallServices = Sets.newHashSet();
+
+ /**
* The list of currently-available call-service selector implementations.
*/
private final List<ICallServiceSelector> mSelectors;
@@ -80,6 +89,12 @@
private final Switchboard mSwitchboard;
+ private final Runnable mNextCallServiceCallback = new Runnable() {
+ @Override public void run() {
+ attemptNextCallService();
+ }
+ };
+
/**
* The iterator over the currently-selected ordered list of call-service descriptors.
*/
@@ -141,6 +156,34 @@
}
/**
+ * Handles the specified compatibility status from the call-service implementation.
+ * TODO(gilad): Consider making this class stateful, potentially rejecting out-of-order/
+ * unexpected invocations (i.e. beyond checking for unexpected call IDs).
+ *
+ * @param callId The ID of the call.
+ * @param isCompatible True if the call-service is compatible with the corresponding call and
+ * false otherwise.
+ */
+ void setIsCompatibleWith(String callId, boolean isCompatible) {
+ if (callId != mCall.getId()) {
+ Log.wtf(this, "setIsCompatibleWith invoked with unexpected call ID: %s", callId);
+ return;
+ }
+
+ if (!mIsAborted) {
+ CallServiceWrapper callService = mCall.getCallService();
+ if (callService != null) {
+ if (isCompatible) {
+ callService.call(mCall.toCallInfo(), mNextCallServiceCallback);
+ return;
+ }
+ mIncompatibleCallServices.add(callService);
+ }
+ attemptNextCallService();
+ }
+ }
+
+ /**
* Aborts the attempt to place the relevant call. Intended to be invoked by
* switchboard through the outgoing-calls manager.
*/
@@ -166,6 +209,9 @@
}
mCall.setState(CallState.DIALING);
+ for (CallServiceWrapper callService : mIncompatibleCallServices) {
+ mCall.addIncompatibleCallService(callService);
+ }
mSwitchboard.handleSuccessfulOutgoingCall(mCall);
}
@@ -263,23 +309,14 @@
final CallServiceWrapper callService =
mCallServicesById.get(descriptor.getCallServiceId());
- if (callService == null) {
+ if (callService == null || mAttemptedCallServices.contains(callService)) {
+ // The next call service is either null or has already been attempted, fast forward
+ // to the next.
attemptNextCallService();
} else {
- BindCallback callback = new BindCallback() {
- @Override public void onSuccess() {
- callService.call(mCall.toCallInfo());
- }
- @Override public void onFailure() {
- attemptNextCallService();
- }
- };
-
+ mAttemptedCallServices.add(callService);
mCall.setCallService(callService);
-
- // TODO(santoscordon): Consider making bind private to CallServiceWrapper and having
- // CSWrapper.call() do the bind automatically.
- callService.bind(callback);
+ callService.isCompatibleWith(mCall.toCallInfo(), mNextCallServiceCallback);
}
} else {
mCallServiceDescriptorIterator = null;
diff --git a/src/com/android/telecomm/OutgoingCallsManager.java b/src/com/android/telecomm/OutgoingCallsManager.java
index 0ed30e6..c37665f 100644
--- a/src/com/android/telecomm/OutgoingCallsManager.java
+++ b/src/com/android/telecomm/OutgoingCallsManager.java
@@ -69,6 +69,24 @@
}
/**
+ * Forwards the compatibility status from the call-service implementation to the corresponding
+ * outgoing-call processor.
+ *
+ * @param callId The ID of the call.
+ * @param isCompatible True if the call-service is compatible with the corresponding call and
+ * false otherwise.
+ */
+ void setCompatibleWith(String callId, boolean isCompatible) {
+ OutgoingCallProcessor processor = mOutgoingCallProcessors.get(callId);
+ if (processor == null) {
+ // Shouldn't happen, so log a wtf if it does.
+ Log.wtf(this, "Received unexpected setCompatibleWith notification.");
+ } else {
+ processor.setCompatibleWith(callId, isCompatible);
+ }
+ }
+
+ /**
* Removes the outgoing call processor mapping for the successful call and returns execution to
* the switchboard. This method is invoked from {@link CallServiceAdapter} after a call service
* has notified Telecomm that it successfully placed the call.
diff --git a/src/com/android/telecomm/ServiceBinder.java b/src/com/android/telecomm/ServiceBinder.java
index 98ce4ca..b5c0050 100644
--- a/src/com/android/telecomm/ServiceBinder.java
+++ b/src/com/android/telecomm/ServiceBinder.java
@@ -44,6 +44,47 @@
public void onFailure();
}
+ /**
+ * Helper class to perform on-demand binding.
+ */
+ final class Binder {
+ /**
+ * Performs an asynchronous bind to the service (only if not already bound) and executes the
+ * specified callback.
+ *
+ * @param callback The callback to notify of the binding's success or failure.
+ */
+ void bind(BindCallback callback) {
+ ThreadUtil.checkOnMainThread();
+ Log.d(ServiceBinder.this, "bind()");
+
+ // Reset any abort request if we're asked to bind again.
+ clearAbort();
+
+ if (!mCallbacks.isEmpty()) {
+ // Binding already in progress, append to the list of callbacks and bail out.
+ mCallbacks.add(callback);
+ return;
+ }
+
+ mCallbacks.add(callback);
+ if (mServiceConnection == null) {
+ Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
+ ServiceConnection connection = new ServiceBinderConnection();
+
+ Log.d(ServiceBinder.this, "Binding to call service with intent: %s", serviceIntent);
+ if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
+ handleFailedConnection();
+ return;
+ }
+ } else {
+ Log.d(ServiceBinder.this, "Service is already bound.");
+ Preconditions.checkNotNull(mBinder);
+ handleSuccessfulConnection();
+ }
+ }
+ }
+
private final class ServiceBinderConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName componentName, IBinder binder) {
@@ -58,8 +99,7 @@
}
mServiceConnection = this;
- mBinder = binder;
- setServiceInterface(binder);
+ setBinder(binder);
handleSuccessfulConnection();
}
@@ -114,45 +154,6 @@
mComponentName = componentName;
}
- /**
- * Performs an asynchronous bind to the service if not already bound.
- *
- * @param callback The callback to notify of the binding's success or failure.
- * @return The result of {#link Context#bindService} or true if already bound.
- */
- final boolean bind(BindCallback callback) {
- ThreadUtil.checkOnMainThread();
- Log.d(this, "bind()");
-
- // Reset any abort request if we're asked to bind again.
- clearAbort();
-
- // If we are already waiting on a binding request, simply append to the list of waiting
- // callbacks.
- if (!mCallbacks.isEmpty()) {
- mCallbacks.add(callback);
- return true;
- }
-
- mCallbacks.add(callback);
- if (mServiceConnection == null) {
- Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
- ServiceConnection connection = new ServiceBinderConnection();
-
- Log.d(this, "Binding to call service with intent: %s", serviceIntent);
- if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
- handleFailedConnection();
- return false;
- }
- } else {
- Log.d(this, "Service is already bound.");
- Preconditions.checkNotNull(mBinder);
- handleSuccessfulConnection();
- }
-
- return true;
- }
-
final void incrementAssociatedCallCount() {
mAssociatedCallCount++;
}
@@ -182,7 +183,7 @@
} else {
mContext.unbindService(mServiceConnection);
mServiceConnection = null;
- mBinder = null;
+ setBinder(null);
}
}
@@ -190,6 +191,15 @@
return mComponentName;
}
+ final boolean isServiceValid(String actionName) {
+ if (mBinder == null) {
+ Log.wtf(this, "%s invoked while service is unbound", actionName);
+ return false;
+ }
+
+ return true;
+ }
+
/**
* Notifies all the outstanding callbacks that the service is successfully bound. The list of
* outstanding callbacks is cleared afterwards.
@@ -216,7 +226,7 @@
* Handles a service disconnection.
*/
private void handleServiceDisconnected() {
- setServiceInterface(null);
+ setBinder(null);
}
private void clearAbort() {
@@ -224,6 +234,16 @@
}
/**
+ * Sets the (private) binder and updates the child class.
+ *
+ * @param binder The new binder value.
+ */
+ private void setBinder(IBinder binder) {
+ mBinder = binder;
+ setServiceInterface(binder);
+ }
+
+ /**
* Sets the service interface after the service is bound or unbound.
*
* @param binder The actual bound service implementation.