Use BindCallback with ServiceBinder.bind().
Incoming calls sequence will need to know when the bind() succeeds so it
no longer makes sense for the wrapper objects to have direct references
to the finder.
Changes included:
- Making the handle* methods of ServiceBinder private implementations
instead of astract.
- Add overriden setServiceInterface() to the wrapper.
- Add simple BindCallback interface used to get notified of bind()
results.
- Update CallServiceRepository to use BindCallback.
Change-Id: I59300e16463e88626df6d055b7fd4be1d850c5f2
diff --git a/src/com/android/telecomm/CallServiceProviderWrapper.java b/src/com/android/telecomm/CallServiceProviderWrapper.java
index 18cff35..0b993d8 100644
--- a/src/com/android/telecomm/CallServiceProviderWrapper.java
+++ b/src/com/android/telecomm/CallServiceProviderWrapper.java
@@ -55,26 +55,16 @@
* @param componentName The component name of the service to bind to.
* @param repository The call-service repository.
*/
- public CallServiceProviderWrapper(ComponentName componentName, CallServiceRepository repository) {
+ public CallServiceProviderWrapper(
+ ComponentName componentName, CallServiceRepository repository) {
+
super(CALL_SERVICE_PROVIDER_ACTION, componentName);
mRepository = repository;
}
/** {@inheritDoc} */
- @Override public void handleSuccessfulConnection(IBinder binder) {
+ @Override protected void setServiceInterface(IBinder binder) {
mServiceInterface = ICallServiceProvider.Stub.asInterface(binder);
- mRepository.processProvider(getComponentName(), this);
- }
-
- /** {@inheritDoc} */
- @Override public void handleFailedConnection() {
- mRepository.abortProvider(getComponentName());
- }
-
- /** {@inheritDoc} */
- @Override public void handleServiceDisconnected() {
- mServiceInterface = null;
- // TODO(santoscordon): fill in.
}
/**
diff --git a/src/com/android/telecomm/CallServiceRepository.java b/src/com/android/telecomm/CallServiceRepository.java
index 28cac6b..eb31d87 100644
--- a/src/com/android/telecomm/CallServiceRepository.java
+++ b/src/com/android/telecomm/CallServiceRepository.java
@@ -31,6 +31,7 @@
import android.telecomm.ICallServiceProvider;
import android.util.Log;
+import com.android.telecomm.ServiceBinder.BindCallback;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -151,11 +152,8 @@
mOutstandingProviders = Sets.newHashSet();
for (ComponentName name : providerNames) {
- // Bind to each of the providers that were found. Some of the providers may already be
- // bound, and in those cases the provider wrapper will still invoke processProvider()
- // allowing us to treat bound and unbound providers the same.
- getProvider(name).bind();
mOutstandingProviders.add(name);
+ bindProvider(name);
}
int providerCount = providerNames.size();
@@ -176,6 +174,29 @@
}
/**
+ * Attempts to bind to the specified provider before continuing to {@link #processProvider}.
+ *
+ * @param componentName The component name of the relevant provider.
+ */
+ private void bindProvider(final ComponentName componentName) {
+ final CallServiceProviderWrapper provider = getProvider(componentName);
+
+ BindCallback callback = new BindCallback() {
+ @Override public void onSuccess() {
+ processProvider(componentName, provider);
+ }
+ @Override public void onFailure() {
+ abortProvider(componentName);
+ }
+ };
+
+ // Some of the providers may already be bound, and in those cases the provider wrapper will
+ // still invoke BindCallback.onSuccess() allowing us to treat bound and unbound providers
+ // the same way.
+ provider.bind(callback);
+ }
+
+ /**
* Returns the all-inclusive list of call-service-provider names.
*
* @return The list containing the (component) names of all known ICallServiceProvider
@@ -206,7 +227,7 @@
* @param providerName The component name of the relevant provider.
* @param provider The provider object to process.
*/
- void processProvider(
+ private void processProvider(
final ComponentName providerName, final CallServiceProviderWrapper provider) {
Preconditions.checkNotNull(providerName);
Preconditions.checkNotNull(provider);
@@ -234,7 +255,7 @@
*
* @param providerName The component name of the relevant provider.
*/
- void abortProvider(ComponentName providerName) {
+ private void abortProvider(ComponentName providerName) {
Preconditions.checkNotNull(providerName);
removeOutstandingProvider(providerName);
}
diff --git a/src/com/android/telecomm/CallServiceWrapper.java b/src/com/android/telecomm/CallServiceWrapper.java
index 2dc5170..74277c4 100644
--- a/src/com/android/telecomm/CallServiceWrapper.java
+++ b/src/com/android/telecomm/CallServiceWrapper.java
@@ -65,27 +65,6 @@
mAdapter = adapter;
}
- /**
- * Initializes the underlying call-service implementation upon successful binding.
- *
- * {@inheritDoc}
- */
- @Override public void handleSuccessfulConnection(IBinder binder) {
- mServiceInterface = ICallService.Stub.asInterface(binder);
- setCallServiceAdapter(mAdapter);
- }
-
- /** {@inheritDoc} */
- @Override public void handleFailedConnection() {
- // TODO(santoscordon): fill in
- }
-
- /** {@inheritDoc} */
- @Override public void handleServiceDisconnected() {
- mServiceInterface = null;
- // TODO(santoscordon): fill in.
- }
-
public CallServiceInfo getInfo() {
return mCallServiceInfo;
}
@@ -141,4 +120,10 @@
Log.e(TAG, "Failed to disconnect call " + callId + ".", e);
}
}
+
+ /** {@inheritDoc} */
+ @Override protected void setServiceInterface(IBinder binder) {
+ mServiceInterface = ICallService.Stub.asInterface(binder);
+ setCallServiceAdapter(mAdapter);
+ }
}
diff --git a/src/com/android/telecomm/ServiceBinder.java b/src/com/android/telecomm/ServiceBinder.java
index 900d18f..c58791c 100644
--- a/src/com/android/telecomm/ServiceBinder.java
+++ b/src/com/android/telecomm/ServiceBinder.java
@@ -25,6 +25,9 @@
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
+import com.google.common.collect.Sets;
+
+import java.util.Set;
/**
* Abstract class to perform the work of binding and unbinding to the specified service interface.
@@ -33,6 +36,14 @@
*/
abstract class ServiceBinder<ServiceInterface extends IInterface> {
+ /**
+ * Callback to notify after a binding succeeds or fails.
+ */
+ interface BindCallback {
+ public void onSuccess();
+ public void onFailure();
+ }
+
private final class ServiceBinderConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName componentName, IBinder binder) {
@@ -42,6 +53,7 @@
if (mIsBindingAborted) {
clearAbort();
mContext.unbindService(this);
+ handleFailedConnection();
return;
}
@@ -68,6 +80,9 @@
/** The component name of the service to bind to. */
private final ComponentName mComponentName;
+ /** The set of callbacks waiting for notification of the binding's success or failure. */
+ private final Set<BindCallback> mCallbacks = Sets.newHashSet();
+
/** Used to bind and unbind from the service. */
private ServiceConnection mServiceConnection;
@@ -98,15 +113,24 @@
/**
* 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() {
+ final boolean bind(BindCallback callback) {
ThreadUtil.checkOnMainThread();
// 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;
+ }
+
if (mServiceConnection == null) {
+ mCallbacks.add(callback);
Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
ServiceConnection connection = new ServiceBinderConnection();
@@ -143,23 +167,46 @@
}
/**
- * Handles a successful attempt to bind to service. See {@link Context#bindService}.
+ * Notifies all the outstanding callbacks that the service is successfully bound. The list of
+ * outstanding callbacks is cleared afterwards.
*
- * @param service The actual bound service implementation.
+ * @param binder The actual bound service implementation.
*/
- protected abstract void handleSuccessfulConnection(IBinder binder);
+ private void handleSuccessfulConnection(IBinder binder) {
+ setServiceInterface(binder);
+
+ for (BindCallback callback : mCallbacks) {
+ callback.onSuccess();
+ }
+ mCallbacks.clear();
+ }
/**
- * Handles a failed attempt to bind to service. See {@link Context#bindService}.
+ * Notifies all the outstanding callbacks that the service failed to bind. The list of
+ * outstanding callbacks is cleared afterwards.
*/
- protected abstract void handleFailedConnection();
+ private void handleFailedConnection() {
+ for (BindCallback callback : mCallbacks) {
+ callback.onFailure();
+ }
+ mCallbacks.clear();
+ }
/**
* Handles a service disconnection.
*/
- protected abstract void handleServiceDisconnected();
+ private void handleServiceDisconnected() {
+ setServiceInterface(null);
+ }
private void clearAbort() {
mIsBindingAborted = false;
}
+
+ /**
+ * Sets the service interface after the service is bound or unbound.
+ *
+ * @param binder The actual bound service implementation.
+ */
+ protected abstract void setServiceInterface(IBinder binder);
}