Use CallServiceWrappers in place of ICallService.
Change-Id: Icd8a6ae2401f68d04b359fb7539b6d4f5aafecd5
diff --git a/src/com/android/telecomm/Call.java b/src/com/android/telecomm/Call.java
index 905fa6a..ea62da4 100644
--- a/src/com/android/telecomm/Call.java
+++ b/src/com/android/telecomm/Call.java
@@ -19,7 +19,6 @@
import android.os.RemoteException;
import android.telecomm.CallInfo;
import android.telecomm.CallState;
-import android.telecomm.ICallService;
import android.util.Log;
import java.util.Date;
@@ -60,7 +59,7 @@
* The call service which is currently connecting this call, null as long as the call is not
* connected.
*/
- private ICallService mCallService;
+ private CallServiceWrapper mCallService;
/**
* Read-only and parcelable version of this call.
@@ -117,11 +116,11 @@
return new Date().getTime() - mCreationTime.getTime();
}
- ICallService getCallService() {
+ CallServiceWrapper getCallService() {
return mCallService;
}
- void setCallService(ICallService callService) {
+ void setCallService(CallServiceWrapper callService) {
mCallService = callService;
}
@@ -132,19 +131,18 @@
setCallService(null);
}
- /*
+ /**
* Attempts to disconnect the call through the call service.
*/
void disconnect() {
if (mCallService == null) {
Log.w(TAG, "disconnect() request on a call without a call service.");
} else {
- try {
- Log.i(TAG, "Send disconnect to call service for call with id " + mId);
- mCallService.disconnect(mId);
- } catch (RemoteException e) {
- Log.e(TAG, "Disconnect attempt failed.", e);
- }
+ Log.i(TAG, "Send disconnect to call service for call with id " + mId);
+ // The call isn't officially disconnected until the call service confirms that the call
+ // was actually disconnected. Only then is the association between call and call service
+ // severed, see {@link CallsManager#markCallAsDisconnected}.
+ mCallService.disconnect(mId);
}
}
diff --git a/src/com/android/telecomm/CallServiceFinder.java b/src/com/android/telecomm/CallServiceFinder.java
deleted file mode 100644
index d24c612..0000000
--- a/src/com/android/telecomm/CallServiceFinder.java
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.telecomm;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.telecomm.ICallService;
-import android.telecomm.ICallServiceLookupResponse;
-import android.telecomm.ICallServiceProvider;
-import android.util.Log;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Finds {@link ICallService} and {@link ICallServiceProvider} implementations on the device.
- * Uses binder APIs to find ICallServiceProviders and calls method on ICallServiceProvider to
- * find ICallService implementations.
- * TODO(santoscordon): Add performance timing to async calls.
- */
-final class CallServiceFinder {
-
- private static final String TAG = CallServiceFinder.class.getSimpleName();
-
- /**
- * The longest period in milliseconds each lookup cycle is allowed to span over, see
- * {@link #mLookupTerminator}.
- * TODO(gilad): Likely requires tuning.
- */
- private static final int LOOKUP_TIMEOUT_MS = 100;
-
- private final Switchboard mSwitchboard;
-
- private final OutgoingCallsManager mOutgoingCallsManager;
-
- /**
- * Determines whether or not a lookup cycle is already running.
- */
- private boolean mIsLookupInProgress = false;
-
- /**
- * The current lookup-cycle ID. Incremented upon initiateLookup calls.
- * TODO(gilad): If at all useful, consider porting the cycle ID concept to switchboard and
- * have it centralized/shared between the two finders.
- */
- private int mLookupId = 0;
-
- /**
- * The set of bound call-services. Only populated via initiateLookup scenarios. Entries should
- * only be removed upon unbinding.
- * TODO(gilad): Add the necessary logic to keep this set up to date.
- */
- private Set<ICallService> mCallServiceRegistry = Sets.newHashSet();
-
- /**
- * The set of bound call-service providers. Only populated via initiateLookup scenarios.
- * Providers should only be removed upon unbinding.
- * TODO(santoscordon): This can be removed once this class starts using CallServiceWrapper
- * since we'll be able to unbind the providers within registerProvider().
- */
- private Set<CallServiceProviderWrapper> mProviderRegistry = Sets.newHashSet();
-
- /**
- * Map of {@link CallServiceProviderWrapper}s keyed by their ComponentName. Used as a long-lived
- * cache in order to simplify management of service-wrapper construction/destruction.
- */
- private Map<ComponentName, CallServiceProviderWrapper> mProviderCache = Maps.newHashMap();
-
- /**
- * Stores the names of the providers to bind to in one lookup cycle. The set size represents
- * the number of call-service providers this finder expects to hear back from upon initiating
- * call-service lookups, see initiateLookup. Whenever all providers respond before the lookup
- * timeout occurs, the complete set of (available) call services is passed to the switchboard
- * for further processing of outgoing calls etc. When the timeout occurs before all responses
- * are received, the partial (potentially empty) set gets passed (to the switchboard) instead.
- * Entries are removed from this set as providers register.
- */
- private Set<ComponentName> mUnregisteredProviders;
-
- /**
- * Used to interrupt lookup cycles that didn't terminate naturally within the allowed
- * period, see LOOKUP_TIMEOUT.
- */
- private final Runnable mLookupTerminator = new Runnable() {
- @Override
- public void run() {
- terminateLookup();
- }
- };
-
- /** Used to run code (e.g. messages, Runnables) on the main (UI) thread. */
- private final Handler mHandler = new Handler(Looper.getMainLooper());
-
- /**
- * Persists the specified parameters.
- *
- * @param switchboard The switchboard for this finder to work against.
- * @param outgoingCallsManager Manager in charge of placing outgoing calls.
- */
- CallServiceFinder(Switchboard switchboard, OutgoingCallsManager outgoingCallsManager) {
- mSwitchboard = switchboard;
- mOutgoingCallsManager = outgoingCallsManager;
- }
-
- /**
- * Initiates a lookup cycle for call-service providers. Must be called from the UI thread.
- * TODO(gilad): Expand this comment to describe the lookup flow in more detail.
- */
- void initiateLookup() {
- ThreadUtil.checkOnMainThread();
- if (mIsLookupInProgress) {
- // At most one active lookup is allowed at any given time, bail out.
- return;
- }
-
- List<ComponentName> providerNames = getProviderNames();
- if (providerNames.isEmpty()) {
- Log.i(TAG, "No ICallServiceProvider implementations found.");
- updateSwitchboard();
- return;
- }
-
- mLookupId++;
- mIsLookupInProgress = true;
- mUnregisteredProviders = 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 registerProvider()
- // allowing us to treat bound and unbound providers the same.
- getProvider(name).bind();
- mUnregisteredProviders.add(name);
- }
-
- int providerCount = providerNames.size();
- int unregisteredProviderCount = mUnregisteredProviders.size();
-
- Log.i(TAG, "Found " + providerCount + " implementations of ICallServiceProvider, "
- + unregisteredProviderCount + " of which are not currently registered.");
-
- if (unregisteredProviderCount == 0) {
- // All known (provider) implementations are already registered, pass control
- // back to the switchboard.
- updateSwitchboard();
- } else {
- // Schedule a lookup terminator to run after LOOKUP_TIMEOUT_MS milliseconds.
- mHandler.removeCallbacks(mLookupTerminator);
- mHandler.postDelayed(mLookupTerminator, LOOKUP_TIMEOUT_MS);
- }
- }
-
- /**
- * Returns the all-inclusive list of call-service-provider names.
- *
- * @return The list containing the (component) names of all known ICallServiceProvider
- * implementations or the empty list upon no available providers.
- */
- private List<ComponentName> getProviderNames() {
- // The list of provider names to return to the caller, may be populated below.
- List<ComponentName> providerNames = Lists.newArrayList();
-
- PackageManager packageManager = TelecommApp.getInstance().getPackageManager();
- Intent intent = new Intent(CallServiceProviderWrapper.CALL_SERVICE_PROVIDER_ACTION);
- for (ResolveInfo entry : packageManager.queryIntentServices(intent, 0)) {
- ServiceInfo serviceInfo = entry.serviceInfo;
- if (serviceInfo != null) {
- // The entry resolves to a proper service, add it to the list of provider names.
- providerNames.add(
- new ComponentName(serviceInfo.packageName, serviceInfo.name));
- }
- }
-
- return providerNames;
- }
-
- /**
- * Queries the supplied provider asynchronously for its CallServices and passes the list through
- * to {@link #registerCallServices} which will relinquish control back to switchboard.
- *
- * @param providerName The component name of the relevant provider.
- * @param provider The provider object to register.
- */
- void registerProvider(
- final ComponentName providerName, final CallServiceProviderWrapper provider) {
-
- // Query the provider for {@link ICallService} implementations.
- provider.lookupCallServices(new ICallServiceLookupResponse.Stub() {
- @Override
- public void setCallServices(final List<IBinder> binderList) {
- // TODO(santoscordon): Do we need Binder.clear/restoreCallingIdentity()?
- mHandler.post(new Runnable() {
- @Override public void run() {
- Set<ICallService> callServices = Sets.newHashSet();
- for (IBinder binder : binderList) {
- callServices.add(ICallService.Stub.asInterface(binder));
- }
- registerCallServices(providerName, provider, callServices);
- }
- });
- }
- });
- }
-
- /**
- * Registers the {@link CallService}s for the specified provider and performs the necessary
- * bookkeeping to potentially return control to the switchboard before the timeout for the
- * current lookup cycle.
- *
- * @param providerName The component name of the relevant provider.
- * @param provider The provider associated with callServices.
- * @param callServices The {@link CallService}s to register.
- */
- private void registerCallServices(
- ComponentName providerName,
- CallServiceProviderWrapper provider,
- Set<ICallService> callServices) {
- ThreadUtil.checkOnMainThread();
-
- if (mUnregisteredProviders.remove(providerName)) {
- mProviderRegistry.add(provider);
-
- // Add all the call services from this provider to the call-service registry.
- for (ICallService callService : callServices) {
- try {
- CallServiceAdapter adapter = new CallServiceAdapter(mOutgoingCallsManager);
- callService.setCallServiceAdapter(adapter);
- mCallServiceRegistry.add(callService);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to set call-service adapter.");
- }
- }
-
- if (mUnregisteredProviders.size() < 1) {
- terminateLookup(); // No other providers to wait for.
- }
- } else {
- Log.i(TAG, "Unexpected list of call services in lookup " + mLookupId + " from " +
- providerName);
- }
- }
-
- /**
- * Unregisters the specified provider.
- *
- * @param providerName The component name of the relevant provider.
- */
- void unregisterProvider(ComponentName providerName) {
- ThreadUtil.checkOnMainThread();
- mProviderRegistry.remove(providerName);
- }
-
- /**
- * Timeouts the current lookup cycle, see LookupTerminator.
- */
- private void terminateLookup() {
- mHandler.removeCallbacks(mLookupTerminator);
- mUnregisteredProviders.clear();
-
- updateSwitchboard();
- mIsLookupInProgress = false;
- }
-
- /**
- * Updates the switchboard passing the relevant call services (as opposed
- * to call-service providers).
- */
- private void updateSwitchboard() {
- ThreadUtil.checkOnMainThread();
- mSwitchboard.setCallServices(mCallServiceRegistry);
- }
-
- /**
- * Returns the call-service provider wrapper for the specified componentName. Creates a new one
- * if none is found in the cache.
- *
- * @param ComponentName The component name of the provider.
- */
- private CallServiceProviderWrapper getProvider(ComponentName componentName) {
- Preconditions.checkNotNull(componentName);
-
- CallServiceProviderWrapper provider = mProviderCache.get(componentName);
- if (provider == null) {
- provider = new CallServiceProviderWrapper(componentName, this);
- mProviderCache.put(componentName, provider);
- }
-
- return provider;
- }
-}
diff --git a/src/com/android/telecomm/CallServiceProviderWrapper.java b/src/com/android/telecomm/CallServiceProviderWrapper.java
index 044d370..18cff35 100644
--- a/src/com/android/telecomm/CallServiceProviderWrapper.java
+++ b/src/com/android/telecomm/CallServiceProviderWrapper.java
@@ -45,28 +45,30 @@
private ICallServiceProvider mServiceInterface;
/**
- * The class to notify when the binding succeeds or fails.
+ * The class to notify when binding succeeds or fails.
*/
- private final CallServiceFinder mFinder;
+ private final CallServiceRepository mRepository;
/**
* 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, CallServiceFinder finder) {
+ public CallServiceProviderWrapper(ComponentName componentName, CallServiceRepository repository) {
super(CALL_SERVICE_PROVIDER_ACTION, componentName);
- mFinder = finder;
+ mRepository = repository;
}
/** {@inheritDoc} */
@Override public void handleSuccessfulConnection(IBinder binder) {
mServiceInterface = ICallServiceProvider.Stub.asInterface(binder);
- mFinder.registerProvider(getComponentName(), this);
+ mRepository.processProvider(getComponentName(), this);
}
/** {@inheritDoc} */
@Override public void handleFailedConnection() {
- mFinder.unregisterProvider(getComponentName());
- // TODO(santoscordon): Notify CallServiceFinder.
+ mRepository.abortProvider(getComponentName());
}
/** {@inheritDoc} */
@@ -75,7 +77,9 @@
// TODO(santoscordon): fill in.
}
- /** See {@link ICallServiceProvider#lookupCallServices}. */
+ /**
+ * See {@link ICallServiceProvider#lookupCallServices}.
+ */
public void lookupCallServices(ICallServiceLookupResponse response) {
try {
if (mServiceInterface == null) {
diff --git a/src/com/android/telecomm/CallServiceRepository.java b/src/com/android/telecomm/CallServiceRepository.java
new file mode 100644
index 0000000..28cac6b
--- /dev/null
+++ b/src/com/android/telecomm/CallServiceRepository.java
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.telecomm;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.telecomm.CallServiceInfo;
+import android.telecomm.ICallService;
+import android.telecomm.ICallServiceLookupResponse;
+import android.telecomm.ICallServiceProvider;
+import android.util.Log;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Uses package manager to find all implementations of {@link ICallServiceProvider} and uses them to
+ * get a list of bindable {@link ICallServices}. Ultimately returns a list of call services as
+ * {@link CallServiceWrapper}s. The resulting call services may or may not be bound at the end of the
+ * lookup.
+ * TODO(santoscordon): Add performance timing to async calls.
+ * TODO(santoscordon): Need to unbind/remove unused call services stored in the cache.
+ */
+final class CallServiceRepository {
+
+ private static final String TAG = CallServiceRepository.class.getSimpleName();
+
+ /**
+ * The longest period in milliseconds each lookup cycle is allowed to span over, see
+ * {@link #mLookupTerminator}.
+ * TODO(gilad): Likely requires tuning.
+ */
+ private static final int LOOKUP_TIMEOUT_MS = 100;
+
+ private final Switchboard mSwitchboard;
+
+ private final OutgoingCallsManager mOutgoingCallsManager;
+
+ /**
+ * Determines whether or not a lookup cycle is already running.
+ */
+ private boolean mIsLookupInProgress = false;
+
+ /**
+ * The current lookup-cycle ID, unique per invocation of {@link #initiateLookup}.
+ */
+ private int mLookupId = 0;
+
+ /**
+ * Map of {@link CallServiceProviderWrapper}s keyed by their ComponentName. Used as a cache for
+ * call services. Entries are added to the cache as part of the lookup sequence. Every call
+ * service found will have an entry in the cache. The cache is cleaned up periodically to
+ * remove any call services (bound or unbound) which are no longer needed because they have no
+ * associated calls. After a cleanup, the only entries in the cache should be call services
+ * with existing calls. During the lookup, we will always use a cached version of a call service
+ * if one exists.
+ */
+ private Map<ComponentName, CallServiceProviderWrapper> mProviderCache = Maps.newHashMap();
+
+ /**
+ * Map of {@link CallServiceWrapper}s keyed by their ComponentName. Used as a long-lived cache
+ * in order to simplify management of service-wrapper construction/destruction.
+ */
+ private Map<ComponentName, CallServiceWrapper> mCallServiceCache = Maps.newHashMap();
+
+ /**
+ * Stores the names of the providers to bind to in one lookup cycle. The set size represents
+ * the number of call-service providers this repository expects to hear back from upon
+ * initiating call-service lookups, see initiateLookup. Whenever all providers respond before
+ * the lookup timeout occurs, the complete set of (available) call services is passed to the
+ * switchboard for further processing of outgoing calls etc. When the timeout occurs before all
+ * responses are received, the partial (potentially empty) set gets passed (to the switchboard)
+ * instead. Entries are removed from this set as providers are processed.
+ */
+ private Set<ComponentName> mOutstandingProviders;
+
+ /**
+ * Used to interrupt lookup cycles that didn't terminate naturally within the allowed
+ * period, see LOOKUP_TIMEOUT.
+ */
+ private final Runnable mLookupTerminator = new Runnable() {
+ @Override
+ public void run() {
+ terminateLookup();
+ }
+ };
+
+ /** Used to run code (e.g. messages, Runnables) on the main (UI) thread. */
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+ /**
+ * Persists the specified parameters.
+ *
+ * @param switchboard The switchboard.
+ * @param outgoingCallsManager Manager in charge of placing outgoing calls.
+ */
+ CallServiceRepository(Switchboard switchboard, OutgoingCallsManager outgoingCallsManager) {
+ mSwitchboard = switchboard;
+ mOutgoingCallsManager = outgoingCallsManager;
+ }
+
+ /**
+ * Initiates a lookup cycle for call-service providers. Must be called from the UI thread.
+ * TODO(gilad): Expand this comment to describe the lookup flow in more detail.
+ *
+ * @param lookupId The switchboard-supplied lookup ID.
+ */
+ void initiateLookup(int lookupId) {
+ ThreadUtil.checkOnMainThread();
+ if (mIsLookupInProgress) {
+ // At most one active lookup is allowed at any given time, bail out.
+ return;
+ }
+
+ List<ComponentName> providerNames = getProviderNames();
+ if (providerNames.isEmpty()) {
+ Log.i(TAG, "No ICallServiceProvider implementations found.");
+ updateSwitchboard();
+ return;
+ }
+
+ mLookupId = lookupId;
+ mIsLookupInProgress = true;
+ 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);
+ }
+
+ int providerCount = providerNames.size();
+ int outstandingProviderCount = mOutstandingProviders.size();
+
+ Log.i(TAG, "Found " + providerCount + " implementations of ICallServiceProvider, "
+ + outstandingProviderCount + " of which are not currently processed.");
+
+ if (outstandingProviderCount == 0) {
+ // All known (provider) implementations are already processed, pass control
+ // back to the switchboard.
+ updateSwitchboard();
+ } else {
+ // Schedule a lookup terminator to run after LOOKUP_TIMEOUT_MS milliseconds.
+ mHandler.removeCallbacks(mLookupTerminator);
+ mHandler.postDelayed(mLookupTerminator, LOOKUP_TIMEOUT_MS);
+ }
+ }
+
+ /**
+ * Returns the all-inclusive list of call-service-provider names.
+ *
+ * @return The list containing the (component) names of all known ICallServiceProvider
+ * implementations or the empty list upon no available providers.
+ */
+ private List<ComponentName> getProviderNames() {
+ // The list of provider names to return to the caller, may be populated below.
+ List<ComponentName> providerNames = Lists.newArrayList();
+
+ PackageManager packageManager = TelecommApp.getInstance().getPackageManager();
+ Intent intent = new Intent(CallServiceProviderWrapper.CALL_SERVICE_PROVIDER_ACTION);
+ for (ResolveInfo entry : packageManager.queryIntentServices(intent, 0)) {
+ ServiceInfo serviceInfo = entry.serviceInfo;
+ if (serviceInfo != null) {
+ // The entry resolves to a proper service, add it to the list of provider names.
+ providerNames.add(
+ new ComponentName(serviceInfo.packageName, serviceInfo.name));
+ }
+ }
+
+ return providerNames;
+ }
+
+ /**
+ * Queries the supplied provider asynchronously for its CallServices and passes the list through
+ * to {@link #processCallServices} which will relinquish control back to switchboard.
+ *
+ * @param providerName The component name of the relevant provider.
+ * @param provider The provider object to process.
+ */
+ void processProvider(
+ final ComponentName providerName, final CallServiceProviderWrapper provider) {
+ Preconditions.checkNotNull(providerName);
+ Preconditions.checkNotNull(provider);
+
+ // Query the provider for {@link ICallService} implementations.
+ provider.lookupCallServices(new ICallServiceLookupResponse.Stub() {
+ // TODO(santoscordon): Rename CallServiceInfo to CallServiceDescriptor and update
+ // this method name to setCallServiceDescriptors.
+ @Override
+ public void setCallServices(final List<CallServiceInfo> callServiceInfos) {
+ // TODO(santoscordon): Do we need Binder.clear/restoreCallingIdentity()?
+ mHandler.post(new Runnable() {
+ @Override public void run() {
+ processCallServices(
+ providerName, provider, Sets.newHashSet(callServiceInfos));
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * Skips the processing of a provider. Called in cases where the provider was not found or
+ * not connected.
+ *
+ * @param providerName The component name of the relevant provider.
+ */
+ void abortProvider(ComponentName providerName) {
+ Preconditions.checkNotNull(providerName);
+ removeOutstandingProvider(providerName);
+ }
+
+ /**
+ * Processes the {@link CallServiceInfo}s for the specified provider and performs the necessary
+ * bookkeeping to potentially return control to the switchboard before the timeout for the
+ * current lookup cycle.
+ *
+ * @param providerName The component name of the relevant provider.
+ * @param provider The provider associated with callServices.
+ * @param callServiceInfos The set of call service infos to process.
+ */
+ private void processCallServices(
+ ComponentName providerName,
+ CallServiceProviderWrapper provider,
+ Set<CallServiceInfo> callServiceInfos) {
+
+ Preconditions.checkNotNull(provider);
+ Preconditions.checkNotNull(callServiceInfos);
+ ThreadUtil.checkOnMainThread();
+
+ // We only need the provider for retrieving the call-service info set, so unbind here.
+ provider.unbind();
+
+ if (mOutstandingProviders.contains(providerName)) {
+ // Add all the call services from this provider to the call-service cache.
+ for (CallServiceInfo info : callServiceInfos) {
+ getCallService(info);
+ }
+
+ removeOutstandingProvider(providerName);
+ } else {
+ Log.i(TAG, "Unexpected list of call services in lookup " + mLookupId + " from " +
+ providerName);
+ }
+ }
+
+ /**
+ * Removes an entry from the set of outstanding providers. When the final outstanding
+ * provider is removed, terminates the lookup.
+ *
+ * @param providerName The component name of the relevant provider.
+ */
+ private void removeOutstandingProvider(ComponentName providerName) {
+ ThreadUtil.checkOnMainThread();
+
+ mOutstandingProviders.remove(providerName);
+ if (mOutstandingProviders.size() < 1) {
+ terminateLookup(); // No other providers to wait for.
+ }
+ }
+
+ /**
+ * Timeouts the current lookup cycle, see LookupTerminator.
+ */
+ private void terminateLookup() {
+ mHandler.removeCallbacks(mLookupTerminator);
+ mOutstandingProviders.clear();
+
+ updateSwitchboard();
+ mIsLookupInProgress = false;
+ }
+
+ /**
+ * Updates the switchboard with the call services from the latest lookup.
+ */
+ private void updateSwitchboard() {
+ ThreadUtil.checkOnMainThread();
+
+ Set<CallServiceWrapper> callServices = Sets.newHashSet(mCallServiceCache.values());
+ mSwitchboard.setCallServices(callServices);
+ }
+
+ /**
+ * Returns the call-service provider wrapper for the specified componentName. Creates a new one
+ * if none is found in the cache.
+ *
+ * @param componentName The component name of the provider.
+ */
+ private CallServiceProviderWrapper getProvider(ComponentName componentName) {
+ Preconditions.checkNotNull(componentName);
+
+ CallServiceProviderWrapper provider = mProviderCache.get(componentName);
+ if (provider == null) {
+ provider = new CallServiceProviderWrapper(componentName, this);
+ mProviderCache.put(componentName, provider);
+ }
+
+ return provider;
+ }
+
+ /**
+ * Creates and returns the call service for the specified call-service info object. Inserts
+ * newly created entries into the cache, see {@link #mCallServiceCache}, or if a cached
+ * version already exists, returns that instead. All newly created instances will not yet
+ * be bound, however cached versions may or may not be bound.
+ *
+ * @param info The call service descriptor.
+ * @return The call service.
+ */
+ private CallServiceWrapper getCallService(CallServiceInfo info) {
+ Preconditions.checkNotNull(info);
+
+ // TODO(santoscordon): Rename getServiceComponent to getComponentName.
+ ComponentName componentName = info.getServiceComponent();
+
+ CallServiceWrapper callService = mCallServiceCache.get(componentName);
+ if (callService == null) {
+ CallServiceAdapter adapter = new CallServiceAdapter(mOutgoingCallsManager);
+ callService = new CallServiceWrapper(info, adapter);
+ mCallServiceCache.put(componentName, callService);
+ }
+
+ return callService;
+ }
+}
diff --git a/src/com/android/telecomm/CallServiceSelectorFinder.java b/src/com/android/telecomm/CallServiceSelectorRepository.java
similarity index 81%
rename from src/com/android/telecomm/CallServiceSelectorFinder.java
rename to src/com/android/telecomm/CallServiceSelectorRepository.java
index 0270e3d..13249c5 100644
--- a/src/com/android/telecomm/CallServiceSelectorFinder.java
+++ b/src/com/android/telecomm/CallServiceSelectorRepository.java
@@ -41,9 +41,9 @@
* asynchronously bind to them. Each lookup cycle is time-boxed, hence selectors too slow
* to bind are effectively omitted from the set that is passed back to {@link Switchboard}.
*/
-final class CallServiceSelectorFinder {
+final class CallServiceSelectorRepository {
- private static final String TAG = CallServiceSelectorFinder.class.getSimpleName();
+ private static final String TAG = CallServiceSelectorRepository.class.getSimpleName();
/**
* The longest period in milliseconds each lookup cycle is allowed to span over, see
@@ -74,17 +74,18 @@
private final Switchboard mSwitchboard;
+ /** The application context. */
+ private final Context mContext;
+
/**
* Determines whether or not a lookup cycle is already running.
*/
private boolean mIsLookupInProgress = false;
/**
- * Used to generate unique lookup-cycle identifiers. Incremented upon initiateLookup calls.
- * TODO(gilad): If at all useful, consider porting the cycle ID concept to switchboard and
- * have it centralized/shared between the two finders.
+ * The current lookup-cycle ID, unique per invocation of {@link #initiateLookup}.
*/
- private int mNextLookupId = 0;
+ private int mLookupId = 0;
/**
* The set of bound call-service selectors. Only populated via initiateLookup scenarios.
@@ -94,54 +95,55 @@
/**
* Stores the names of the selectors to bind to in one lookup cycle. The set size represents
- * the number of call-service selectors this finder expects to hear back from upon initiating
- * lookups, see initiateLookup. Whenever all selectors respond before the timeout occurs, the
- * complete set of available selectors is passed to the switchboard for further processing of
- * outgoing calls etc. When the timeout occurs before all responds are received, the partial
- * (potentially empty) set gets passed to the switchboard instead. Note that cached selectors
- * do not require finding and hence are excluded from this set. Also note that selectors are
- * removed from this set as they register.
+ * the number of call-service selectors this repositories expects to hear back from upon
+ * initiating lookups, see initiateLookup. Whenever all selectors respond before the timeout
+ * occurs, the complete set of available selectors is passed to the switchboard for further
+ * processing of outgoing calls etc. When the timeout occurs before all responds are received,
+ * the partial (potentially empty) set gets passed to the switchboard instead. Note that cached
+ * selectors do not require finding and hence are excluded from this set. Also note that
+ * selectors are removed from this set as they register.
*/
private Set<ComponentName> mUnregisteredSelectors;
/**
- * Persists the specified parameters.
+ * Persists the specified parameters and initializes the new instance.
*
* @param switchboard The switchboard for this finer to work against.
*/
- CallServiceSelectorFinder(Switchboard switchboard) {
+ CallServiceSelectorRepository(Switchboard switchboard) {
mSwitchboard = switchboard;
+ mContext = TelecommApp.getInstance();
}
/**
* Initiates a lookup cycle for call-service selectors. Must be called from the UI thread.
*
- * @param context The relevant application context.
+ * @param lookupId The switchboard-supplied lookup ID.
*/
- void initiateLookup(Context context) {
+ void initiateLookup(int lookupId) {
ThreadUtil.checkOnMainThread();
if (mIsLookupInProgress) {
// At most one active lookup is allowed at any given time, bail out.
return;
}
- List<ComponentName> selectorNames = getSelectorNames(context);
+ List<ComponentName> selectorNames = getSelectorNames();
if (selectorNames.isEmpty()) {
Log.i(TAG, "No ICallServiceSelector implementations found.");
updateSwitchboard();
return;
}
+ mLookupId = lookupId;
mIsLookupInProgress = true;
mUnregisteredSelectors = Sets.newHashSet();
- int lookupId = mNextLookupId++;
for (ComponentName name : selectorNames) {
if (!mSelectorRegistry.contains(name)) {
// The selector is either not yet registered or has been unregistered
// due to unbinding etc.
mUnregisteredSelectors.add(name);
- bindSelector(name, lookupId, context);
+ bindSelector(name, lookupId);
}
}
@@ -163,17 +165,14 @@
}
/**
- * Returns the all-inclusive list of call-service selector names.
- *
- * @param context The relevant/application context to query against.
* @return The list containing the (component) names of all known ICallServiceSelector
* implementations or the empty list upon no available selectors.
*/
- private List<ComponentName> getSelectorNames(Context context) {
+ private List<ComponentName> getSelectorNames() {
// The list of selector names to return to the caller, may be populated below.
List<ComponentName> selectorNames = Lists.newArrayList();
- PackageManager packageManager = context.getPackageManager();
+ PackageManager packageManager = mContext.getPackageManager();
Intent intent = new Intent(CALL_SERVICE_SELECTOR_CLASS_NAME);
for (ResolveInfo entry : packageManager.queryIntentServices(intent, 0)) {
ServiceInfo serviceInfo = entry.serviceInfo;
@@ -193,13 +192,11 @@
*
* @param selectorName The component name of the relevant selector.
* @param lookupId The lookup-cycle ID.
- * @param context The relevant application context.
*/
private void bindSelector(
- final ComponentName selectorName, final int lookupId, Context context) {
+ final ComponentName selectorName, final int lookupId) {
Preconditions.checkNotNull(selectorName);
- Preconditions.checkNotNull(context);
Intent serviceIntent =
new Intent(CALL_SERVICE_SELECTOR_CLASS_NAME).setComponent(selectorName);
@@ -219,7 +216,7 @@
}
};
- if (!context.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
+ if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
// TODO(gilad): Handle error.
}
}
@@ -270,4 +267,4 @@
mSwitchboard.setSelectors(mSelectorRegistry);
mIsLookupInProgress = false;
}
-}
\ No newline at end of file
+}
diff --git a/src/com/android/telecomm/CallServiceWrapper.java b/src/com/android/telecomm/CallServiceWrapper.java
index c7b494f..2dc5170 100644
--- a/src/com/android/telecomm/CallServiceWrapper.java
+++ b/src/com/android/telecomm/CallServiceWrapper.java
@@ -20,6 +20,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.telecomm.CallInfo;
+import android.telecomm.CallServiceInfo;
import android.telecomm.ICallService;
import android.telecomm.ICallServiceAdapter;
import android.util.Log;
@@ -32,10 +33,6 @@
* TODO(santoscordon): Look into combining with android.telecomm.CallService.
*/
public class CallServiceWrapper extends ServiceBinder<ICallService> {
- private static final String TAG = CallServiceWrapper.class.getSimpleName();
-
- /** The actual service implementation. */
- private ICallService mServiceInterface;
/**
* The service action used to bind to ICallService implementations.
@@ -43,22 +40,44 @@
*/
static final String CALL_SERVICE_ACTION = ICallService.class.getName();
+ private static final String TAG = CallServiceWrapper.class.getSimpleName();
+
+ /** The descriptor of this call service as supplied by the call-service provider. */
+ private final CallServiceInfo mCallServiceInfo;
+
+ /**
+ * The adapter used by the underlying call-service implementation to communicate with Telecomm.
+ */
+ private final CallServiceAdapter mAdapter;
+
+ /** The actual service implementation. */
+ private ICallService mServiceInterface;
+
/**
* Creates a call-service provider for the specified component.
+ *
+ * @param info The call-service descriptor from {@link ICallServiceProvider#lookupCallServices}.
+ * @param adapter The call-service adapter.
*/
- public CallServiceWrapper(ComponentName componentName) {
- super(CALL_SERVICE_ACTION, componentName);
+ public CallServiceWrapper(CallServiceInfo info, CallServiceAdapter adapter) {
+ super(CALL_SERVICE_ACTION, info.getServiceComponent());
+ mCallServiceInfo = info;
+ mAdapter = adapter;
}
- /** {@inheritDoc} */
+ /**
+ * Initializes the underlying call-service implementation upon successful binding.
+ *
+ * {@inheritDoc}
+ */
@Override public void handleSuccessfulConnection(IBinder binder) {
mServiceInterface = ICallService.Stub.asInterface(binder);
- // TODO(santoscordon): Notify CallServiceFinder.
+ setCallServiceAdapter(mAdapter);
}
/** {@inheritDoc} */
@Override public void handleFailedConnection() {
- // TODO(santoscordon): Notify CallServiceFinder.
+ // TODO(santoscordon): fill in
}
/** {@inheritDoc} */
@@ -67,6 +86,10 @@
// TODO(santoscordon): fill in.
}
+ public CallServiceInfo getInfo() {
+ return mCallServiceInfo;
+ }
+
/** See {@link ICallService#setCallServiceAdapter}. */
public void setCallServiceAdapter(ICallServiceAdapter callServiceAdapter) {
try {
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index c96b8da..d69af53 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -104,7 +104,7 @@
// No objection to issue the call, proceed with trying to put it through.
Call call = new Call(handle, contactInfo);
- mSwitchboard.placeOutgoingCall(call, context);
+ mSwitchboard.placeOutgoingCall(call);
}
/**
@@ -197,7 +197,11 @@
*/
void markCallAsDisconnected(String callId) {
setCallState(callId, CallState.DISCONNECTED);
- mCalls.remove(callId);
+
+ Call call = mCalls.remove(callId);
+ // At this point the call service has confirmed that the call is disconnected to it is
+ // safe to disassociate the call from its call service.
+ call.clearCallService();
// Notify the in-call UI
mInCallController.markCallAsDisconnected(callId);
diff --git a/src/com/android/telecomm/OutgoingCallProcessor.java b/src/com/android/telecomm/OutgoingCallProcessor.java
index 5135326..0a2df04 100644
--- a/src/com/android/telecomm/OutgoingCallProcessor.java
+++ b/src/com/android/telecomm/OutgoingCallProcessor.java
@@ -25,7 +25,7 @@
import android.os.RemoteException;
import android.telecomm.CallInfo;
import android.telecomm.CallState;
-import android.telecomm.ICallService;
+import android.telecomm.CallServiceInfo;
import android.telecomm.ICallServiceSelectionResponse;
import android.telecomm.ICallServiceSelector;
import android.util.Log;
@@ -37,7 +37,7 @@
/**
* Utility class to place a call using the specified set of call-services and ordered selectors.
- * Iterates through the selectors and gets a sorted list of supported call service IDs for each
+ * Iterates through the selectors and gets a sorted list of supported call service infos for each
* selector. Upon receiving each sorted list (one list per selector), each of the corresponding
* call services is then attempted until either the outgoing call is placed, the attempted call
* is aborted (by the switchboard), or the list is exhausted -- whichever occurs first.
@@ -57,14 +57,14 @@
private final Call mCall;
/**
- * The duplicate-free list of currently-available call-service IDs.
+ * The duplicate-free list of currently-available call-service infos.
*/
- private final List<String> mCallServiceIds = Lists.newArrayList();
+ private final List<CallServiceInfo> mCallServiceInfos = Lists.newArrayList();
/**
- * The map of currently-available call-service implementations keyed by call-service ID.
+ * The map of currently-available call-service implementations keyed by call-service infos.
*/
- private final Map<String, ICallService> mCallServicesById = Maps.newHashMap();
+ private final Map<CallServiceInfo, CallServiceWrapper> mCallServicesByInfo = Maps.newHashMap();
/**
* The set of currently-available call-service selector implementations.
@@ -80,9 +80,9 @@
private final Switchboard mSwitchboard;
/**
- * The iterator over the currently-selected ordered list of call-service IDs.
+ * The iterator over the currently-selected ordered list of call-service infos.
*/
- private Iterator<String> mCallServiceIdIterator;
+ private Iterator<CallServiceInfo> mCallServiceInfoIterator;
private Iterator<ICallServiceSelector> mSelectorIterator;
@@ -90,14 +90,14 @@
* The last call service which we asked to place the call. If null, it indicates that there
* exists no call service that we expect to place this call.
*/
- private ICallService mCallService;
+ private CallServiceWrapper mCallService;
private boolean mIsAborted = false;
/**
* Persists the specified parameters and iterates through the prioritized list of selectors
* passing to each selector (read-only versions of) the call object and all available call-
- * service IDs. Stops once a matching selector is found. Calls with no matching selectors
+ * service infos. Stops once a matching selector is found. Calls with no matching selectors
* will eventually be killed by the cleanup/monitor switchboard handler, which will in turn
* call the abort method of this processor via {@link OutgoingCallsManager}.
*
@@ -109,7 +109,7 @@
*/
OutgoingCallProcessor(
Call call,
- Set<ICallService> callServices,
+ Set<CallServiceWrapper> callServices,
List<ICallServiceSelector> selectors,
OutgoingCallsManager outgoingCallsManager,
Switchboard switchboard) {
@@ -124,13 +124,12 @@
mOutgoingCallsManager = outgoingCallsManager;
mSwitchboard = switchboard;
- // Populate the list and map of call-service IDs. The list is needed since
+ // Populate the list and map of call-service infos. The list is needed since
// it's being passed down to selectors.
- for (ICallService callService : callServices) {
- // TOOD(gilad): Implement callService.getId() and use that instead.
- String id = "xyz";
- mCallServiceIds.add(id);
- mCallServicesById.put(id, callService);
+ for (CallServiceWrapper callService : callServices) {
+ CallServiceInfo info = callService.getInfo();
+ mCallServiceInfos.add(info);
+ mCallServicesByInfo.put(info, callService);
}
}
@@ -140,7 +139,7 @@
void process() {
ThreadUtil.checkOnMainThread();
- if (mSelectors.isEmpty() || mCallServiceIds.isEmpty()) {
+ if (mSelectors.isEmpty() || mCallServiceInfos.isEmpty()) {
// TODO(gilad): Consider adding a failure message/type to differentiate the various
// cases, or potentially throw an exception in this case.
mOutgoingCallsManager.handleFailedOutgoingCall(mCall);
@@ -197,7 +196,7 @@
ICallServiceSelector selector = mSelectorIterator.next();
ICallServiceSelectionResponse.Stub response = createSelectionResponse();
try {
- selector.select(mCall.toCallInfo(), mCallServiceIds, response);
+ selector.select(mCall.toCallInfo(), mCallServiceInfos, response);
} catch (RemoteException e) {
attemptNextSelector();
}
@@ -212,12 +211,12 @@
*/
private ICallServiceSelectionResponse.Stub createSelectionResponse() {
return new ICallServiceSelectionResponse.Stub() {
- @Override public void setSelectedCallServiceIds(
- final List<String> selectedCallServiceIds) {
+ @Override public void setSelectedCallServiceInfos(
+ final List<CallServiceInfo> selectedCallServiceInfos) {
Runnable runnable = new Runnable() {
@Override public void run() {
- processSelectedCallServiceIds(selectedCallServiceIds);
+ processSelectedCallServiceInfos(selectedCallServiceInfos);
}
};
@@ -227,24 +226,24 @@
}
/**
- * Persists the ordered-list of call service IDs as selected by the current selector and
+ * Persists the ordered-list of call-service infos as selected by the current selector and
* starts iterating through the corresponding call services in the continuing attempt to
* place the call.
*
- * @selectedCallServiceIds The (ordered) list of call service IDs.
+ * @selectedCallServiceInfos The (ordered) list of call service infos.
*/
- private void processSelectedCallServiceIds(List<String> selectedCallServiceIds) {
- if (selectedCallServiceIds == null || selectedCallServiceIds.isEmpty()) {
+ private void processSelectedCallServiceInfos(List<CallServiceInfo> selectedCallServiceInfos) {
+ if (selectedCallServiceInfos == null || selectedCallServiceInfos.isEmpty()) {
attemptNextSelector();
- } else if (mCallServiceIdIterator == null) {
- mCallServiceIdIterator = selectedCallServiceIds.iterator();
+ } else if (mCallServiceInfoIterator == null) {
+ mCallServiceInfoIterator = selectedCallServiceInfos.iterator();
attemptNextCallService();
}
}
/**
- * Attempts to place the call using the call service specified by the next call-service ID of
- * mCallServiceIdIterator. If there are no more call services to attempt, the process continues
+ * Attempts to place the call using the call service specified by the next call-service info of
+ * mCallServiceInfoIterator. If there are no more call services to attempt, the process continues
* to the next call-service selector via {@link #attemptNextSelector}.
*/
private void attemptNextCallService() {
@@ -252,21 +251,16 @@
return;
}
- if (mCallServiceIdIterator.hasNext()) {
- String id = mCallServiceIdIterator.next();
- mCallService = mCallServicesById.get(id);
+ if (mCallServiceInfoIterator.hasNext()) {
+ CallServiceInfo info = mCallServiceInfoIterator.next();
+ mCallService = mCallServicesByInfo.get(info);
if (mCallService == null) {
attemptNextCallService();
} else {
- try {
- mCallService.call(mCall.toCallInfo());
- } catch (RemoteException e) {
- // TODO(gilad): Log etc.
- attemptNextCallService();
- }
+ mCallService.call(mCall.toCallInfo());
}
} else {
- mCallServiceIdIterator = null;
+ mCallServiceInfoIterator = null;
resetCallService();
attemptNextSelector();
}
diff --git a/src/com/android/telecomm/OutgoingCallsManager.java b/src/com/android/telecomm/OutgoingCallsManager.java
index 7eae0fa..247af8c 100644
--- a/src/com/android/telecomm/OutgoingCallsManager.java
+++ b/src/com/android/telecomm/OutgoingCallsManager.java
@@ -16,7 +16,6 @@
package com.android.telecomm;
-import android.telecomm.ICallService;
import android.telecomm.ICallServiceSelector;
import android.util.Log;
@@ -59,7 +58,7 @@
* @param selectors The ordered list of selectors used in placing the call.
*/
void placeCall(
- Call call, Set<ICallService> callServices, List<ICallServiceSelector> selectors) {
+ Call call, Set<CallServiceWrapper> callServices, List<ICallServiceSelector> selectors) {
Log.i(TAG, "Placing an outgoing call (" + call.getId() + ")");
diff --git a/src/com/android/telecomm/Switchboard.java b/src/com/android/telecomm/Switchboard.java
index d4afb76..32ef914 100644
--- a/src/com/android/telecomm/Switchboard.java
+++ b/src/com/android/telecomm/Switchboard.java
@@ -23,7 +23,6 @@
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
-import android.telecomm.ICallService;
import android.telecomm.ICallServiceSelector;
import java.util.Collection;
@@ -31,9 +30,9 @@
import java.util.Set;
/**
- * Switchboard is responsible for (1) selecting the {@link ICallService} through which to make
- * outgoing calls and (2) switching active calls between transports (each ICallService is
- * considered a different transport type).
+ * Switchboard is responsible for (1) gathering the {@link CallServiceWrapper}s and
+ * {@link ICallServiceSelector}s through which to place outgoing calls, (2) starting outgoing calls
+ * (via {@link OutgoingCallsManager} and (3) switching active calls between call services.
*/
final class Switchboard {
@@ -48,9 +47,9 @@
/** Used to place outgoing calls. */
private final OutgoingCallsManager mOutgoingCallsManager;
- private CallServiceFinder mCallServiceFinder;
+ private final CallServiceRepository mCallServiceRepository;
- private CallServiceSelectorFinder mSelectorFinder;
+ private final CallServiceSelectorRepository mSelectorRepository;
/** Used to schedule tasks on the main (UI) thread. */
private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -75,66 +74,63 @@
private final Set<Call> mPendingOutgoingCalls = Sets.newLinkedHashSet();
/**
- * The set of currently available call-service implementations, see {@link CallServiceFinder}.
- * TODO(gilad): Null out once the active-call count goes to zero.
+ * The set of currently available call service implementations, see
+ * {@link CallServiceRepository}. Populated after a lookup for call services as part of
+ * {@link #placeCall}. It is cleared periodically when there are no more new or pending outgoing
+ * calls.
*/
- private Set<ICallService> mCallServices;
+ private Set<CallServiceWrapper> mCallServices;
/**
* The set of currently available call-service-selector implementations,
- * see {@link CallServiceSelectorFinder}.
+ * see {@link CallServiceSelectorRepository}.
* TODO(gilad): Null out once the active-call count goes to zero.
*/
private Set<ICallServiceSelector> mSelectors;
/**
+ * The current lookup-cycle ID used with the repositories. Incremented with each invocation
+ * of {@link #placeCall} and passed to the repositories via initiateLookup().
+ */
+ private int mLookupId = 0;
+
+ /**
* Persists the specified parameters and initializes Switchboard.
*/
Switchboard(CallsManager callsManager) {
mCallsManager = callsManager;
mOutgoingCallsManager = new OutgoingCallsManager(this);
- mCallServiceFinder = new CallServiceFinder(this, mOutgoingCallsManager);
- mSelectorFinder = new CallServiceSelectorFinder(this);
+ mCallServiceRepository = new CallServiceRepository(this, mOutgoingCallsManager);
+ mSelectorRepository = new CallServiceSelectorRepository(this);
}
/**
- * Attempts to place an outgoing call to the specified handle.
+ * Starts the process of placing an outgoing call by searching for available call services
+ * through which the call can be placed. After a lookup for those services completes, execution
+ * returns to {@link #setCallServices} where the process of placing the call continues.
*
* @param call The yet-to-be-connected outgoing-call object.
- * @param context The application context.
*/
- void placeOutgoingCall(Call call, Context context) {
+ void placeOutgoingCall(Call call) {
ThreadUtil.checkOnMainThread();
- boolean bailout = false;
- if (isNullOrEmpty(mCallServices)) {
- mCallServiceFinder.initiateLookup();
- bailout = true;
- }
- if (isNullOrEmpty(mSelectors)) {
- mSelectorFinder.initiateLookup(context);
- bailout = true;
- }
+ mLookupId++;
- if (bailout) {
- // Unable to process the call without either call service, selectors, or both.
- // Store the call for deferred processing and bail out.
- mNewOutgoingCalls.add(call);
- return;
- }
-
- processNewOutgoingCall(call);
+ // We initialize a lookup every time because between calls the set of available call
+ // services can change between calls.
+ mCallServiceRepository.initiateLookup(mLookupId);
+ mSelectorRepository.initiateLookup(mLookupId);
}
/**
* Persists the specified set of call services and attempts to place any pending outgoing
- * calls. Intended to be invoked by {@link CallServiceFinder} exclusively.
+ * calls. Intended to be invoked by {@link CallServiceRepository} exclusively.
*
* @param callServices The potentially-partial set of call services. Partial since the lookup
* process is time-boxed, such that some providers/call-services may be slow to respond and
* hence effectively omitted from the specified list.
*/
- void setCallServices(Set<ICallService> callServices) {
+ void setCallServices(Set<CallServiceWrapper> callServices) {
ThreadUtil.checkOnMainThread();
mCallServices = callServices;
@@ -143,13 +139,15 @@
/**
* Persists the specified list of selectors and attempts to connect any pending outgoing
- * calls. Intended to be invoked by {@link CallServiceSelectorFinder} exclusively.
+ * calls. Intended to be invoked by {@link CallServiceSelectorRepository} exclusively.
*
* @param selectors The potentially-partial set of selectors. Partial since the lookup
* procedure is time-boxed such that some selectors may be slow to respond and hence
* effectively omitted from the specified set.
*/
void setSelectors(Set<ICallServiceSelector> selectors) {
+ // TODO(santoscordon): This should take in CallServiceSelectorWrapper instead of the direct
+ // ICallServiceSelector implementation. Copy what we have for CallServiceWrapper.
ThreadUtil.checkOnMainThread();
// TODO(gilad): Add logic to include the built-in selectors (e.g. for dealing with
@@ -207,6 +205,8 @@
*/
private void tick() {
// TODO(gilad): More here.
+ // TODO(santoscordon): Clear mCallServices if there exist no more new or pending outgoing
+ // calls.
}
/**
@@ -235,7 +235,6 @@
* @param call The call to place.
*/
private void processNewOutgoingCall(Call call) {
-
Preconditions.checkNotNull(mCallServices);
Preconditions.checkNotNull(mSelectors);