Updating the outgoing call sequence.
- Removes OutgoingCallsManager
- Call now invokes it's own OutgoingCallProcessor (OCP) directly.
- Results for select(), call(), and OCP.process() now happen through
new AsyncResultCallback closure objects specified at the time
the methods are invoked.
- Move remaining outgoing call responsibilities in Switchboard to
OCP including expiration and CS/selector discovery.
- Remove isCompatibleWith sequence
Change-Id: Ie63c7900dc7a324d0c56e0767ed19b2ef0868528
diff --git a/src/com/android/telecomm/AsyncResultCallback.java b/src/com/android/telecomm/AsyncResultCallback.java
new file mode 100644
index 0000000..d059c6c
--- /dev/null
+++ b/src/com/android/telecomm/AsyncResultCallback.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2014, 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;
+
+/**
+ * Generic result interface for use with async method callback.
+ */
+interface AsyncResultCallback<T> {
+ void onResult(T param1);
+}
diff --git a/src/com/android/telecomm/Call.java b/src/com/android/telecomm/Call.java
index d86a8f9..995957c 100644
--- a/src/com/android/telecomm/Call.java
+++ b/src/com/android/telecomm/Call.java
@@ -127,6 +127,12 @@
/** Set of listeners on this call. */
private Set<Listener> mListeners = Sets.newHashSet();
+ private OutgoingCallProcessor mOutgoingCallProcessor;
+
+ // TODO(santoscordon): The repositories should be changed into singleton types.
+ private CallServiceRepository mCallServiceRepository;
+ private CallServiceSelectorRepository mSelectorRepository;
+
/**
* Creates an empty call object.
*
@@ -379,14 +385,33 @@
}
/**
- * Starts the outgoing call flow through the switchboard. When switchboard completes, it will
- * invoke handleSuccessful/FailedOutgoingCall.
+ * Starts the outgoing call sequence. Upon completion, there should exist an active connection
+ * through a call service (or the call will have failed).
*/
void startOutgoing() {
- Switchboard.getInstance().placeOutgoingCall(this);
+ Preconditions.checkState(mOutgoingCallProcessor == null);
+
+ mOutgoingCallProcessor = new OutgoingCallProcessor(
+ this,
+ Switchboard.getInstance().getCallServiceRepository(),
+ Switchboard.getInstance().getSelectorRepository(),
+ new AsyncResultCallback<Boolean>() {
+ @Override
+ public void onResult(Boolean wasCallPlaced) {
+ if (wasCallPlaced) {
+ handleSuccessfulOutgoing();
+ } else {
+ handleFailedOutgoing(mOutgoingCallProcessor.isAborted());
+ }
+ mOutgoingCallProcessor = null;
+ }
+ });
+ mOutgoingCallProcessor.process();
}
void handleSuccessfulOutgoing() {
+ setState(CallState.DIALING);
+
// TODO(santoscordon): Replace this with state transitions related to "connecting".
for (Listener l : mListeners) {
l.onSuccessfulOutgoingCall(this);
@@ -394,14 +419,13 @@
}
void handleFailedOutgoing(boolean isAborted) {
- if (isAborted) {
- finalizeAbort();
- }
-
// TODO(santoscordon): Replace this with state transitions related to "connecting".
for (Listener l : mListeners) {
l.onFailedOutgoingCall(this, isAborted);
}
+
+ clearCallService();
+ clearCallServiceSelector();
}
/**
@@ -431,20 +455,6 @@
}
/**
- * Issues an abort signal to the associated call service and clears the current call service
- * and call-service selector.
- */
- void finalizeAbort() {
- Preconditions.checkState(mState == CallState.NEW);
-
- if (mCallService != null) {
- mCallService.abort(this);
- }
- clearCallService();
- clearCallServiceSelector();
- }
-
- /**
* Plays the specified DTMF tone.
*/
void playDtmfTone(char digit) {
@@ -473,16 +483,8 @@
*/
void disconnect() {
if (mState == CallState.NEW) {
- // There is a very strange indirection here. When we are told to disconnect, we issue
- // an 'abort' to the switchboard if we are still in the NEW (or "connecting") state.
- // The switchboard will then cancel the outgoing call process and ask this class to
- // finalize the abort procedure via {@link #finalizeAbort}. The issue is that
- // Switchboard edits the state of the call as part of the process and then this class
- // is responsible for undoing it, and that is all kinds of backwards.
- // TODO(santoscordon): Remove Switchboard's requirement to edit the state of the Call
- // objects and remove any multi-class shared state of incoming and outgoing call
- // processing.
- Switchboard.getInstance().abortCall(this);
+ Log.v(this, "Aborting call %s", this);
+ abort();
} else if (mState != CallState.ABORTED && mState != CallState.DISCONNECTED) {
Preconditions.checkNotNull(mCallService);
@@ -494,6 +496,12 @@
}
}
+ void abort() {
+ if (mOutgoingCallProcessor != null) {
+ mOutgoingCallProcessor.abort();
+ }
+ }
+
/**
* Answers the call if it is ringing.
*/
diff --git a/src/com/android/telecomm/CallIdMapper.java b/src/com/android/telecomm/CallIdMapper.java
index 7044d89..7f92067 100644
--- a/src/com/android/telecomm/CallIdMapper.java
+++ b/src/com/android/telecomm/CallIdMapper.java
@@ -52,6 +52,11 @@
mCalls.inverse().remove(call);
}
+ void removeCall(String callId) {
+ ThreadUtil.checkOnMainThread();
+ mCalls.remove(callId);
+ }
+
String getCallId(Call call) {
ThreadUtil.checkOnMainThread();
Preconditions.checkNotNull(call);
@@ -70,6 +75,10 @@
return mCalls.get(callId);
}
+ void clear() {
+ mCalls.clear();
+ }
+
void checkValidCallId(String callId) {
// Note, no need for thread check, this method is thread safe.
if (!isValidCallId(callId)) {
diff --git a/src/com/android/telecomm/CallServiceRepository.java b/src/com/android/telecomm/CallServiceRepository.java
index 0589358..f6e1164 100644
--- a/src/com/android/telecomm/CallServiceRepository.java
+++ b/src/com/android/telecomm/CallServiceRepository.java
@@ -160,16 +160,11 @@
}
}
- private final OutgoingCallsManager mOutgoingCallsManager;
private final IncomingCallsManager mIncomingCallsManager;
private final Handler mHandler = new Handler();
/** Persists specified parameters. */
- CallServiceRepository(
- OutgoingCallsManager outgoingCallsManager,
- IncomingCallsManager incomingCallsManager) {
-
- mOutgoingCallsManager = outgoingCallsManager;
+ CallServiceRepository(IncomingCallsManager incomingCallsManager) {
mIncomingCallsManager = incomingCallsManager;
}
@@ -191,7 +186,6 @@
@Override
protected CallServiceWrapper onCreateNewServiceWrapper(ComponentName componentName,
Object param) {
- return new CallServiceWrapper(
- (CallServiceDescriptor) param, mOutgoingCallsManager, mIncomingCallsManager);
+ return new CallServiceWrapper((CallServiceDescriptor) param, mIncomingCallsManager);
}
}
diff --git a/src/com/android/telecomm/CallServiceSelectorRepository.java b/src/com/android/telecomm/CallServiceSelectorRepository.java
index 99a2f52..0a8deb6 100644
--- a/src/com/android/telecomm/CallServiceSelectorRepository.java
+++ b/src/com/android/telecomm/CallServiceSelectorRepository.java
@@ -38,23 +38,6 @@
*/
final class CallServiceSelectorRepository extends BaseRepository<CallServiceSelectorWrapper> {
- private final OutgoingCallsManager mOutgoingCallsManager;
-
- /**
- * The set of call-service selectors. Only populated via initiateLookup scenarios.
- */
- private final Map<ComponentName, CallServiceSelectorWrapper> mCallServiceSelectors =
- Maps.newHashMap();
-
- /**
- * Persists the specified parameters and initializes the new instance.
- *
- * @param outgoingCallsManager The outgoing calls manager.
- */
- CallServiceSelectorRepository(OutgoingCallsManager outgoingCallsManager) {
- mOutgoingCallsManager = outgoingCallsManager;
- }
-
/** {@inheritDoc} */
@Override
protected void onLookupServices(LookupCallback<CallServiceSelectorWrapper> callback) {
@@ -84,20 +67,7 @@
protected CallServiceSelectorWrapper onCreateNewServiceWrapper(
ComponentName componentName, Object param) {
- return new CallServiceSelectorWrapper(
- componentName, CallsManager.getInstance(), mOutgoingCallsManager);
- }
-
- /**
- * Creates a wrapper for the specified component name and starts listening to it's unbind event.
- *
- * @param componentName The component name of the call-service selector.
- * @return The wrapper for the selector.
- */
- private CallServiceSelectorWrapper createWrapper(ComponentName componentName) {
- CallServiceSelectorWrapper selector = new CallServiceSelectorWrapper(
- componentName, CallsManager.getInstance(), mOutgoingCallsManager);
- return selector;
+ return new CallServiceSelectorWrapper(componentName, CallsManager.getInstance());
}
/**
diff --git a/src/com/android/telecomm/CallServiceSelectorWrapper.java b/src/com/android/telecomm/CallServiceSelectorWrapper.java
index 74073df..7cc01a2 100644
--- a/src/com/android/telecomm/CallServiceSelectorWrapper.java
+++ b/src/com/android/telecomm/CallServiceSelectorWrapper.java
@@ -32,7 +32,9 @@
import com.android.internal.telecomm.ICallServiceSelector;
import com.android.internal.telecomm.ICallServiceSelectorAdapter;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* Wrapper for {@link ICallServiceSelector}s, handles binding and keeps track of when the object can
@@ -52,15 +54,17 @@
case MSG_SET_SELECTED_CALL_SERVICES: {
SomeArgs args = (SomeArgs) msg.obj;
try {
- Call call = mCallIdMapper.getCall(args.arg1);
- List<CallServiceDescriptor> descriptors =
- (List<CallServiceDescriptor>) args.arg2;
- if (call != null) {
- mOutgoingCallsManager.processSelectedCallServices(call,
- descriptors);
+ String callId = (String) args.arg1;
+ if (mPendingSelects.containsKey(callId)) {
+ @SuppressWarnings("unchecked")
+ List<CallServiceDescriptor> descriptors =
+ (List<CallServiceDescriptor>) args.arg2;
+
+ mCallIdMapper.removeCall(callId);
+ mPendingSelects.remove(callId).onResult(descriptors);
} else {
Log.w(this, "setSelectedCallServices: unknown call: %s, id: %s",
- call, args.arg1);
+ callId, args.arg1);
}
} finally {
args.recycle();
@@ -70,7 +74,7 @@
case MSG_CANCEL_OUTGOING_CALL: {
Call call = mCallIdMapper.getCall(msg.obj);
if (call != null) {
- mOutgoingCallsManager.abort(call);
+ call.abort();
} else {
Log.w(this, "cancelOutgoingCall: unknown call: %s, id: %s", call,
msg.obj);
@@ -128,9 +132,9 @@
private final Binder mBinder = new Binder();
private final CallIdMapper mCallIdMapper = new CallIdMapper("CallServiceSelector");
private final Adapter mAdapter = new Adapter();
-
private final CallsManager mCallsManager;
- private final OutgoingCallsManager mOutgoingCallsManager;
+ private final Map<String, AsyncResultCallback<List<CallServiceDescriptor>>> mPendingSelects =
+ new HashMap<>();
private ICallServiceSelector mSelectorInterface;
@@ -141,17 +145,12 @@
* @param action The action used to bind to the selector.
* @param componentName The component name of the service.
* @param callsManager The calls manager.
- * @param outgoingCallsManager The outgoing calls manager.
*/
CallServiceSelectorWrapper(
- String action,
- ComponentName componentName,
- CallsManager callsManager,
- OutgoingCallsManager outgoingCallsManager) {
+ String action, ComponentName componentName, CallsManager callsManager) {
super(action, componentName);
mCallsManager = callsManager;
- mOutgoingCallsManager = outgoingCallsManager;
}
/**
@@ -160,17 +159,9 @@
*
* @param componentName The component name of the service.
* @param callsManager The calls manager.
- * @param outgoingCallsManager The outgoing calls manager.
*/
- CallServiceSelectorWrapper(
- ComponentName componentName,
- CallsManager callsManager,
- OutgoingCallsManager outgoingCallsManager) {
-
- this(TelecommConstants.ACTION_CALL_SERVICE_SELECTOR,
- componentName,
- callsManager,
- outgoingCallsManager);
+ CallServiceSelectorWrapper(ComponentName componentName, CallsManager callsManager) {
+ this(TelecommConstants.ACTION_CALL_SERVICE_SELECTOR, componentName, callsManager);
}
/**
@@ -180,25 +171,31 @@
* @param call The call being placed using the {@link CallService}s.
* @param descriptors The descriptors of the available {@link CallService}s with which to place
* the call.
- * @param errorCallback The callback to invoke upon failure.
+ * @param resultCallback The callback on which to return the result.
*/
- void select(final Call call, final List<CallServiceDescriptor> descriptors,
- final Runnable errorCallback) {
+ void select(
+ final Call call,
+ final List<CallServiceDescriptor> descriptors,
+ final AsyncResultCallback<List<CallServiceDescriptor>> resultCallback) {
+
BindCallback callback = new BindCallback() {
@Override
public void onSuccess() {
- if (isServiceValid("select")) {
- try {
- CallInfo callInfo = call.toCallInfo(mCallIdMapper.getCallId(call));
- mSelectorInterface.select(callInfo, descriptors);
- } catch (RemoteException e) {
- }
+ String callId = mCallIdMapper.getCallId(call);
+ mPendingSelects.put(callId, resultCallback);
+
+ try {
+ CallInfo callInfo = call.toCallInfo(mCallIdMapper.getCallId(call));
+ mSelectorInterface.select(callInfo, descriptors);
+ } catch (RemoteException e) {
+ mCallIdMapper.removeCall(call);
+ mPendingSelects.get(callId).onResult(null);
}
}
@Override
public void onFailure() {
- errorCallback.run();
+ resultCallback.onResult(null);
}
};
diff --git a/src/com/android/telecomm/CallServiceWrapper.java b/src/com/android/telecomm/CallServiceWrapper.java
index a4e3d24..4040e33 100644
--- a/src/com/android/telecomm/CallServiceWrapper.java
+++ b/src/com/android/telecomm/CallServiceWrapper.java
@@ -36,6 +36,8 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Set;
/**
@@ -46,7 +48,6 @@
final class CallServiceWrapper extends ServiceBinder<ICallService> {
private final class Adapter extends ICallServiceAdapter.Stub {
- private static final int MSG_SET_IS_COMPATIBLE_WITH = 0;
private static final int MSG_NOTIFY_INCOMING_CALL = 1;
private static final int MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL = 2;
private static final int MSG_HANDLE_FAILED_OUTGOING_CALL = 3;
@@ -61,20 +62,11 @@
public void handleMessage(Message msg) {
Call call;
switch (msg.what) {
- case MSG_SET_IS_COMPATIBLE_WITH:
- call = mCallIdMapper.getCall(msg.obj);
- if (call != null && !call.isIncoming()) {
- mOutgoingCallsManager.setIsCompatibleWith(call,
- msg.arg1 == 1 ? true : false);
- } else {
- Log.w(this, "setIsCompatibleWith, unknown call: %s, id: %s", call,
- msg.obj);
- }
- break;
case MSG_NOTIFY_INCOMING_CALL:
CallInfo clientCallInfo = (CallInfo) msg.obj;
call = mCallIdMapper.getCall(clientCallInfo.getId());
- if (call != null && mPendingCalls.remove(call) && call.isIncoming()) {
+ if (call != null && mPendingIncomingCalls.remove(call) &&
+ call.isIncoming()) {
CallInfo callInfo = new CallInfo(null, clientCallInfo.getState(),
clientCallInfo.getHandle());
mIncomingCallsManager.handleSuccessfulIncomingCall(call, callInfo);
@@ -84,28 +76,27 @@
clientCallInfo.getId());
}
break;
- case MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL:
- call = mCallIdMapper.getCall(msg.obj);
- if (call != null && mPendingCalls.remove(call) && !call.isIncoming()) {
- mOutgoingCallsManager.handleSuccessfulCallAttempt(call);
+ case MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL: {
+ String callId = (String) msg.obj;
+ if (mPendingOutgoingCalls.containsKey(callId)) {
+ mPendingOutgoingCalls.remove(callId).onResult(true);
} else {
- // TODO(gilad): Figure out how to wire up the callService.abort() call.
- Log.w(this,
- "handleSuccessfulOutgoingCall, unknown call: %s, id: %s",
- call, msg.obj);
+ Log.w(this, "handleSuccessfulOutgoingCall, unknown call: %s", callId);
}
break;
+ }
case MSG_HANDLE_FAILED_OUTGOING_CALL: {
SomeArgs args = (SomeArgs) msg.obj;
try {
- call = mCallIdMapper.getCall(args.arg1);
+ String callId = (String) args.arg1;
String reason = (String) args.arg2;
- if (call != null && mPendingCalls.remove(call) && !call.isIncoming()) {
- mOutgoingCallsManager.handleFailedCallAttempt(call, reason);
+ // TODO(santoscordon): Do something with 'reason' or get rid of it.
+
+ if (mPendingOutgoingCalls.containsKey(callId)) {
+ mPendingOutgoingCalls.remove(callId).onResult(false);
+ mCallIdMapper.removeCall(callId);
} else {
- Log.w(this,
- "handleFailedOutgoingCall, unknown call: %s, id: %s",
- call, args.arg1);
+ Log.w(this, "handleFailedOutgoingCall, unknown call: %s", callId);
}
} finally {
args.recycle();
@@ -168,10 +159,7 @@
/** {@inheritDoc} */
@Override
public void setIsCompatibleWith(String callId, boolean isCompatible) {
- Log.v(this, "setIsCompatibleWith id: %s, isCompatible: %b", callId, isCompatible);
- mCallIdMapper.checkValidCallId(callId);
- mHandler.obtainMessage(MSG_SET_IS_COMPATIBLE_WITH, isCompatible ? 1 : 0, 0, callId).
- sendToTarget();
+ Log.wtf(this, "Not expected.");
}
/** {@inheritDoc} */
@@ -184,6 +172,7 @@
/** {@inheritDoc} */
@Override
public void handleSuccessfulOutgoingCall(String callId) {
+ Log.d(this, "handleSuccessfulOutgoingCall %s", callId);
mCallIdMapper.checkValidCallId(callId);
mHandler.obtainMessage(MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL, callId).sendToTarget();
}
@@ -192,6 +181,7 @@
@Override
public void handleFailedOutgoingCall(String callId, String reason) {
mCallIdMapper.checkValidCallId(callId);
+ Log.d(this, "handleFailedOutgoingCall %d", callId);
SomeArgs args = SomeArgs.obtain();
args.arg1 = callId;
args.arg2 = reason;
@@ -241,11 +231,11 @@
private final Adapter mAdapter = new Adapter();
private final CallsManager mCallsManager = CallsManager.getInstance();
- private final Set<Call> mPendingCalls = Sets.newHashSet();
+ private final Set<Call> mPendingIncomingCalls = Sets.newHashSet();
private final CallServiceDescriptor mDescriptor;
private final CallIdMapper mCallIdMapper = new CallIdMapper("CallService");
- private final OutgoingCallsManager mOutgoingCallsManager;
private final IncomingCallsManager mIncomingCallsManager;
+ private final Map<String, AsyncResultCallback<Boolean>> mPendingOutgoingCalls = new HashMap<>();
private Binder mBinder = new Binder();
private ICallService mServiceInterface;
@@ -255,17 +245,14 @@
*
* @param descriptor The call-service descriptor from
* {@link ICallServiceProvider#lookupCallServices}.
- * @param outgoingCallsManager Manages the placing of outgoing calls.
* @param incomingCallsManager Manages the incoming call initialization flow.
*/
CallServiceWrapper(
CallServiceDescriptor descriptor,
- OutgoingCallsManager outgoingCallsManager,
IncomingCallsManager incomingCallsManager) {
super(TelecommConstants.ACTION_CALL_SERVICE, descriptor.getServiceComponent());
mDescriptor = descriptor;
mIncomingCallsManager = incomingCallsManager;
- mOutgoingCallsManager = outgoingCallsManager;
}
CallServiceDescriptor getDescriptor() {
@@ -283,60 +270,48 @@
}
/**
- * 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 errorCallback The callback to invoke upon failure.
+ * Attempts to place the specified call, see {@link ICallService#call}. Returns the result
+ * asynchronously through the specified callback.
*/
- void isCompatibleWith(final Call call, final Runnable errorCallback) {
- Log.d(this, "isCompatibleWith(%s) via %s.", call, getComponentName());
+ void call(final Call call, final AsyncResultCallback<Boolean> resultCallback) {
+ Log.d(this, "call(%s) via %s.", call, getComponentName());
BindCallback callback = new BindCallback() {
@Override
public void onSuccess() {
- if (isServiceValid("isCompatibleWith")) {
- try {
- mPendingCalls.add(call);
- CallInfo callInfo = call.toCallInfo(mCallIdMapper.getCallId(call));
- mServiceInterface.isCompatibleWith(callInfo);
- } catch (RemoteException e) {
- }
+ String callId = mCallIdMapper.getCallId(call);
+ mPendingOutgoingCalls.put(callId, resultCallback);
+
+ try {
+ CallInfo callInfo = call.toCallInfo(callId);
+ mServiceInterface.call(callInfo);
+ } catch (RemoteException e) {
+ mPendingOutgoingCalls.remove(callId).onResult(false);
}
}
@Override
public void onFailure() {
- errorCallback.run();
+ resultCallback.onResult(false);
}
};
mBinder.bind(callback);
}
- /**
- * 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.
- */
- void call(Call call) {
- Log.d(this, "call(%s) via %s.", call, getComponentName());
- if (isServiceValid("call")) {
- try {
- CallInfo callInfo = call.toCallInfo(mCallIdMapper.getCallId(call));
- mServiceInterface.call(callInfo);
- } catch (RemoteException e) {
- }
- }
- }
-
/** @see CallService#abort(String) */
void abort(Call call) {
- mPendingCalls.remove(call);
+ // Clear out any pending outgoing call data
+ String callId = mCallIdMapper.getCallId(call);
+
+ // If still bound, tell the call service to abort.
if (isServiceValid("abort")) {
try {
- mServiceInterface.abort(mCallIdMapper.getCallId(call));
+ mServiceInterface.abort(callId);
} catch (RemoteException e) {
}
}
+
+ removeCall(call);
}
/** @see CallService#hold(String) */
@@ -386,7 +361,7 @@
@Override
public void onSuccess() {
if (isServiceValid("setIncomingCallId")) {
- mPendingCalls.add(call);
+ mPendingIncomingCalls.add(call);
try {
mServiceInterface.setIncomingCallId(mCallIdMapper.getCallId(call),
extras);
@@ -467,7 +442,14 @@
}
void removeCall(Call call) {
- mPendingCalls.remove(call);
+ mPendingIncomingCalls.remove(call);
+
+ AsyncResultCallback<Boolean> outgoingResultCallback =
+ mPendingOutgoingCalls.remove(mCallIdMapper.getCallId(call));
+ if (outgoingResultCallback != null) {
+ outgoingResultCallback.onResult(false);
+ }
+
mCallIdMapper.removeCall(call);
}
@@ -492,22 +474,27 @@
* Called when the associated call service dies.
*/
private void handleCallServiceDeath() {
- if (!mPendingCalls.isEmpty()) {
+ if (!mPendingOutgoingCalls.isEmpty()) {
+ for (AsyncResultCallback<Boolean> callback : mPendingOutgoingCalls.values()) {
+ callback.onResult(false);
+ }
+ mPendingOutgoingCalls.clear();
+ }
+
+ if (!mPendingIncomingCalls.isEmpty()) {
// Iterate through a copy because the code inside the loop will modify the original
// list.
- for (Call call : ImmutableList.copyOf(mPendingCalls)) {
- if (call.isIncoming()) {
- mIncomingCallsManager.handleFailedIncomingCall(call);
- } else {
- mOutgoingCallsManager.handleFailedCallAttempt(call,
- "Call service disconnected.");
- }
+ for (Call call : ImmutableList.copyOf(mPendingIncomingCalls)) {
+ Preconditions.checkState(call.isIncoming());
+ mIncomingCallsManager.handleFailedIncomingCall(call);
}
- if (!mPendingCalls.isEmpty()) {
+ if (!mPendingIncomingCalls.isEmpty()) {
Log.wtf(this, "Pending calls did not get cleared.");
- mPendingCalls.clear();
+ mPendingIncomingCalls.clear();
}
}
+
+ mCallIdMapper.clear();
}
}
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index 85b9340..a4b2086 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -311,6 +311,8 @@
* the user hitting the end-call button.
*/
void disconnectCall(Call call) {
+ Log.v(this, "disconnectCall %s", call);
+
if (!mCalls.contains(call)) {
Log.w(this, "Unknown call (%s) asked to disconnect", call);
} else {
diff --git a/src/com/android/telecomm/OutgoingCallProcessor.java b/src/com/android/telecomm/OutgoingCallProcessor.java
index 3874bd5..0f77567 100644
--- a/src/com/android/telecomm/OutgoingCallProcessor.java
+++ b/src/com/android/telecomm/OutgoingCallProcessor.java
@@ -16,12 +16,17 @@
package com.android.telecomm;
+import android.content.ComponentName;
+import android.os.Handler;
+import android.os.Message;
import android.telecomm.CallServiceDescriptor;
+import com.android.telecomm.BaseRepository.LookupCallback;
import com.google.android.collect.Sets;
-import com.google.common.collect.Lists;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
@@ -44,17 +49,14 @@
*/
final class OutgoingCallProcessor {
+ private final static int MSG_EXPIRE = 1;
+
/**
* The outgoing call this processor is tasked with placing.
*/
private final Call mCall;
/**
- * The duplicate-free list of currently-available call-service descriptors.
- */
- private final List<CallServiceDescriptor> mCallServiceDescriptors = Lists.newArrayList();
-
- /**
* The map of currently-available call-service implementations keyed by call-service ID.
*/
private final Map<String, CallServiceWrapper> mCallServicesById = Maps.newHashMap();
@@ -65,38 +67,40 @@
*/
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();
+ private final CallServiceRepository mCallServiceRepository;
- /**
- * The list of currently-available call-service selector implementations.
- */
- private final Collection<CallServiceSelectorWrapper> mSelectors;
+ private final CallServiceSelectorRepository mSelectorRepository;
- /** Manages all outgoing call processors. */
- private final OutgoingCallsManager mOutgoingCallsManager;
-
- private final Runnable mNextCallServiceCallback = new Runnable() {
- @Override public void run() {
- attemptNextCallService();
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_EXPIRE:
+ abort();
+ break;
+ }
}
};
- private final Runnable mNextSelectorCallback = new Runnable() {
- @Override public void run() {
- attemptNextSelector();
- }
- };
+ /**
+ * The duplicate-free list of currently-available call-service descriptors.
+ */
+ private List<CallServiceDescriptor> mCallServiceDescriptors;
/**
* The iterator over the currently-selected ordered list of call-service descriptors.
*/
private Iterator<CallServiceDescriptor> mCallServiceDescriptorIterator;
+ /**
+ * The list of currently-available call-service selector implementations.
+ */
+ private Collection<CallServiceSelectorWrapper> mSelectors;
+
private Iterator<CallServiceSelectorWrapper> mSelectorIterator;
+ private AsyncResultCallback<Boolean> mResultCallback;
+
private boolean mIsAborted = false;
/**
@@ -107,29 +111,22 @@
* in turn call the abort method of this processor via {@link OutgoingCallsManager}.
*
* @param call The call to place.
- * @param callServices The available call-service implementations.
- * @param selectors The available call-service selector implementations.
- * @param outgoingCallsManager Manager of all outgoing call processors.
+ * @param callServiceRepository
+ * @param selectorRepository
+ * @param resultCallback The callback on which to return the result.
*/
OutgoingCallProcessor(
Call call,
- Collection<CallServiceWrapper> callServices,
- Collection<CallServiceSelectorWrapper> selectors,
- OutgoingCallsManager outgoingCallsManager) {
+ CallServiceRepository callServiceRepository,
+ CallServiceSelectorRepository selectorRepository,
+ AsyncResultCallback<Boolean> resultCallback) {
ThreadUtil.checkOnMainThread();
mCall = call;
- mSelectors = selectors;
- mOutgoingCallsManager = outgoingCallsManager;
-
- // Populate the list and map of call-service descriptors. The list is needed since
- // it's being passed down to selectors.
- for (CallServiceWrapper callService : callServices) {
- CallServiceDescriptor descriptor = callService.getDescriptor();
- mCallServiceDescriptors.add(descriptor);
- mCallServicesById.put(descriptor.getCallServiceId(), callService);
- }
+ mResultCallback = resultCallback;
+ mCallServiceRepository = callServiceRepository;
+ mSelectorRepository = selectorRepository;
}
/**
@@ -138,42 +135,30 @@
void process() {
Log.v(this, "process, mIsAborted: %b", mIsAborted);
if (!mIsAborted) {
- // Only process un-aborted calls.
- ThreadUtil.checkOnMainThread();
+ // Start the expiration timeout.
+ mHandler.sendEmptyMessageDelayed(MSG_EXPIRE, Timeouts.getNewOutgoingCallMillis());
- if (mSelectorIterator == null) {
- mSelectorIterator = mSelectors.iterator();
- attemptNextSelector();
- }
- }
- }
-
- /**
- * 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 isCompatible True if the call-service is compatible with the corresponding call and
- * false otherwise.
- */
- void setIsCompatibleWith(Call call, boolean isCompatible) {
- Log.v(this, "setIsCompatibleWith, call: %s, isCompatible: %b", call, isCompatible);
- if (call != mCall) {
- Log.wtf(this, "setIsCompatibleWith invoked with unexpected call: %s, expected call: %s",
- call, mCall);
- return;
- }
-
- if (!mIsAborted) {
- CallServiceWrapper callService = mCall.getCallService();
- if (callService != null) {
- if (isCompatible) {
- callService.call(mCall);
- return;
+ // Lookup call services
+ mCallServiceRepository.lookupServices(new LookupCallback<CallServiceWrapper>() {
+ @Override
+ public void onComplete(Collection<CallServiceWrapper> services) {
+ setCallServices(services);
}
- mIncompatibleCallServices.add(callService);
+ });
+
+ if (mCall.getCallServiceSelector() == null) {
+ // Lookup selectors
+ mSelectorRepository.lookupServices(
+ new LookupCallback<CallServiceSelectorWrapper>() {
+ @Override
+ public void onComplete(
+ Collection<CallServiceSelectorWrapper> selectors) {
+ setSelectors(selectors);
+ }
+ });
+ } else {
+ setSelectors(ImmutableList.of(mCall.getCallServiceSelector()));
}
- attemptNextCallService();
}
}
@@ -184,31 +169,43 @@
void abort() {
Log.v(this, "abort");
ThreadUtil.checkOnMainThread();
- if (!mIsAborted) {
+ if (!mIsAborted && mResultCallback != null) {
mIsAborted = true;
- // This will also clear the call's call service and selector.
- mOutgoingCallsManager.handleFailedOutgoingCall(mCall, true /* isAborted */);
+
+ // On an abort, we need to check if we already told the call service to place the
+ // call. If so, we need to tell it to abort.
+ // TODO(santoscordon): The call service is saved with the call and so we have to query
+ // the call to get it, which is a bit backwards. Ideally, the call service would be
+ // saved inside this class until the whole thing is complete and then set on the call.
+ CallServiceWrapper callService = mCall.getCallService();
+ if (callService != null) {
+ callService.abort(mCall);
+ }
+
+ sendResult(false);
}
}
+ boolean isAborted() {
+ return mIsAborted;
+ }
+
/**
* Completes the outgoing call sequence by setting the call service on the call object. This is
* invoked when the call service adapter receives positive confirmation that the call service
* placed the call.
*/
- void handleSuccessfulCallAttempt() {
+ void handleSuccessfulCallAttempt(CallServiceWrapper callService) {
Log.v(this, "handleSuccessfulCallAttempt");
ThreadUtil.checkOnMainThread();
if (mIsAborted) {
// TODO(gilad): Ask the call service to drop the call?
+ callService.abort(mCall);
return;
}
- for (CallServiceWrapper callService : mIncompatibleCallServices) {
- mCall.addIncompatibleCallService(callService);
- }
- mCall.handleSuccessfulOutgoing();
+ sendResult(true);
}
/**
@@ -243,6 +240,78 @@
}
/**
+ * Sets the call services to attempt for this outgoing call.
+ *
+ * @param callServices The call services.
+ */
+ private void setCallServices(Collection<CallServiceWrapper> callServices) {
+ mCallServiceDescriptors = new ArrayList<>();
+
+ // Populate the list and map of call-service descriptors. The list is needed since
+ // it's being passed down to selectors.
+ for (CallServiceWrapper callService : callServices) {
+ CallServiceDescriptor descriptor = callService.getDescriptor();
+ mCallServiceDescriptors.add(descriptor);
+ mCallServicesById.put(descriptor.getCallServiceId(), callService);
+ }
+
+ onLookupComplete();
+ }
+
+ /**
+ * Sets the selectors to attemnpt for this outgoing call.
+ *
+ * @param selectors The call-service selectors.
+ */
+ private void setSelectors(Collection<CallServiceSelectorWrapper> selectors) {
+ mSelectors = adjustForEmergencyCalls(selectors);
+ onLookupComplete();
+ }
+
+ private void onLookupComplete() {
+ if (!mIsAborted && mSelectors != null && mCallServiceDescriptors != null) {
+ if (mSelectorIterator == null) {
+ mSelectorIterator = mSelectors.iterator();
+ attemptNextSelector();
+ }
+ }
+ }
+
+ /**
+ * Updates the specified collection of selectors to accomodate for emergency calls and any
+ * preferred selectors specified in the call object.
+ *
+ * @param selectors The selectors found through the selector repository.
+ */
+ private Collection<CallServiceSelectorWrapper> adjustForEmergencyCalls(
+ Collection<CallServiceSelectorWrapper> selectors) {
+ boolean useEmergencySelector =
+ EmergencyCallServiceSelector.shouldUseSelector(mCall.getHandle());
+ Log.d(this, "processNewOutgoingCall, isEmergency=%b", useEmergencySelector);
+
+ if (useEmergencySelector) {
+ // This is potentially an emergency call so add the emergency selector before the
+ // other selectors.
+ ImmutableList.Builder<CallServiceSelectorWrapper> selectorsBuilder =
+ ImmutableList.builder();
+
+ ComponentName componentName = new ComponentName(
+ TelecommApp.getInstance(), EmergencyCallServiceSelector.class);
+ CallServiceSelectorWrapper emergencySelector =
+ new CallServiceSelectorWrapper(
+ componentName.flattenToShortString(),
+ componentName,
+ CallsManager.getInstance());
+
+ selectorsBuilder.add(emergencySelector);
+ selectorsBuilder.addAll(selectors);
+ selectors = selectorsBuilder.build();
+ }
+
+ return selectors;
+ }
+
+ /**
* Attempts to place the call using the next selector, no-op if no other selectors
* are available.
*/
@@ -255,11 +324,17 @@
if (mSelectorIterator.hasNext()) {
CallServiceSelectorWrapper selector = mSelectorIterator.next();
mCall.setCallServiceSelector(selector);
- selector.select(mCall, mCallServiceDescriptors, mNextSelectorCallback);
+ selector.select(mCall, mCallServiceDescriptors,
+ new AsyncResultCallback<List<CallServiceDescriptor>>() {
+ @Override
+ public void onResult(List<CallServiceDescriptor> descriptors) {
+ processSelectedCallServices(descriptors);
+ }
+ });
} else {
Log.v(this, "attemptNextSelector, no more selectors, failing");
mCall.clearCallServiceSelector();
- mOutgoingCallsManager.handleFailedOutgoingCall(mCall, false /* isAborted */);
+ sendResult(false);
}
}
@@ -287,7 +362,25 @@
} else {
mAttemptedCallServices.add(callService);
mCall.setCallService(callService);
- callService.isCompatibleWith(mCall, mNextCallServiceCallback);
+
+ // Increment the associated call count until we get a result. This prevents the call
+ // service from unbinding while we are using it.
+ callService.incrementAssociatedCallCount();
+
+ callService.call(mCall, new AsyncResultCallback<Boolean>() {
+ @Override
+ public void onResult(Boolean wasCallPlaced) {
+ if (wasCallPlaced) {
+ handleSuccessfulCallAttempt(callService);
+ } else {
+ handleFailedCallAttempt("call failed.");
+ }
+
+ // If successful, the call should not have it's own association to keep
+ // the call service bound.
+ callService.decrementAssociatedCallCount();
+ }
+ });
}
} else {
mCallServiceDescriptorIterator = null;
@@ -295,4 +388,15 @@
attemptNextSelector();
}
}
+
+ private void sendResult(boolean wasCallPlaced) {
+ if (mResultCallback != null) {
+ mResultCallback.onResult(wasCallPlaced);
+ mResultCallback = null;
+
+ mHandler.removeMessages(MSG_EXPIRE);
+ } else {
+ Log.wtf(this, "Attempting to return outgoing result twice for call %s", mCall);
+ }
+ }
}
diff --git a/src/com/android/telecomm/OutgoingCallsManager.java b/src/com/android/telecomm/OutgoingCallsManager.java
deleted file mode 100644
index 05bdad0..0000000
--- a/src/com/android/telecomm/OutgoingCallsManager.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright 2014, 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.telecomm.CallServiceDescriptor;
-
-import com.android.internal.telecomm.ICallServiceSelector;
-import com.google.common.collect.Maps;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Responsible for placing all outgoing calls. For each outgoing call, this class creates an
- * instance of {@link OutgoingCallProcessor} which handles the details of connecting to the
- * appropriate call service and placing the call. This class maintains a mapping from call
- * to {@link OutgoingCallProcessor} so that other classes (CallServiceAdapter, etc),
- * can simply call into this class instead of individual OutgoingCallProcessors.
- */
-final class OutgoingCallsManager {
-
- /**
- * Maps call to {@link OutgoingCallProcessor}s.
- */
- private Map<Call, OutgoingCallProcessor> mOutgoingCallProcessors = Maps.newHashMap();
-
- /**
- * Starts the process of placing a call by constructing an outgoing call processor and asking
- * it to place the call. Upon success, execution will continue (via {@link CallServiceAdapter})
- * to {@link #handleSuccessfulCallAttempt}. Upon failure, execution will return to
- * {@link #handleFailedCallAttempt}.
- *
- * @param call The call to place.
- * @param callServices The collection of call services which can potentially place the call.
- * @param selectors The ordered list of selectors used in placing the call.
- */
- void placeCall(
- Call call,
- Collection<CallServiceWrapper> callServices,
- Collection<CallServiceSelectorWrapper> selectors) {
-
- Log.i(this, "Placing an outgoing call: %s", call);
-
- // Create the processor for this (outgoing) call and store it in a map such that call
- // attempts can be aborted etc.
- // TODO(gilad): Consider passing mSelector as an immutable set.
- OutgoingCallProcessor processor =
- new OutgoingCallProcessor(call, callServices, selectors, this);
-
- mOutgoingCallProcessors.put(call, processor);
- processor.process();
- }
-
- /**
- * Forwards the compatibility status from the call-service to the corresponding outgoing-call
- * processor.
- *
- * @param isCompatible True if the call-service is compatible with the call.
- */
- void setIsCompatibleWith(Call call, boolean isCompatible) {
- Log.v(this, "setIsCompatibleWith, call %s, isCompatible: %b", call, isCompatible);
- OutgoingCallProcessor processor = mOutgoingCallProcessors.get(call);
- if (processor == null) {
- // Shouldn't happen, so log a wtf if it does.
- Log.wtf(this, "Received unexpected setCompatibleWith notification.");
- } else {
- processor.setIsCompatibleWith(call, isCompatible);
- }
- }
-
- /**
- * Removes the outgoing call processor mapping for the successful call and returns execution to
- * the call. This method is invoked from {@link CallServiceAdapter} after a call service
- * has notified Telecomm that it successfully placed the call.
- */
- void handleSuccessfulCallAttempt(Call call) {
- Log.v(this, "handleSuccessfulCallAttempt, call: %s", call);
- OutgoingCallProcessor processor = mOutgoingCallProcessors.remove(call);
-
- if (processor == null) {
- // Shouldn't happen, so log a wtf if it does.
- Log.wtf(this, "Received an unexpected placed-call notification.");
- } else {
- processor.handleSuccessfulCallAttempt();
- }
- }
-
- /**
- * Notifies the appropriate outgoing call processor that a call attempt to place the call has
- * failed and the processor should continue attempting to place the call with the next call
- * service. This method is called from {@link CallServiceAdapter} after a call service has
- * notified Telecomm that it could not place the call.
- *
- * @param reason The call-service supplied reason for the failed call attempt.
- */
- void handleFailedCallAttempt(Call call, String reason) {
- Log.v(this, "handleFailedCallAttempt, call: %s, reason: %s", call, reason);
- OutgoingCallProcessor processor = mOutgoingCallProcessors.get(call);
-
- if (processor == null) {
- // Shouldn't happen, so log a wtf if it does.
- Log.wtf(this, "Received an unexpected failed-call notification.");
- } else {
- processor.handleFailedCallAttempt(reason);
- }
- }
-
- /**
- * Removes the outgoing call processor mapping for the failed call and returns execution to the
- * call. In contrast to handleFailedCallAttempt which comes from the call-service and
- * goes to the outgoing-call processor indicating a single failed call attempt, this method is
- * invoked by the outgoing-call processor to indicate that the entire process has failed and we
- * should cleanup and notify the call.
- *
- * @param call The failed outgoing call.
- * @param isAborted True if the call timedout and is aborted.
- */
- void handleFailedOutgoingCall(Call call, boolean isAborted) {
- Log.v(this, "handleFailedOutgoingCall, call: %s", call);
- mOutgoingCallProcessors.remove(call);
- call.handleFailedOutgoing(isAborted);
- }
-
- /**
- * Forwards the selected call service from the selector to the corresponding outgoing-call
- * processor.
- */
- void processSelectedCallServices(Call call, List<CallServiceDescriptor> descriptors) {
- Log.v(this, "processSelectedCallServices, call %s, descriptors: %s", call, descriptors);
- OutgoingCallProcessor processor = mOutgoingCallProcessors.get(call);
- if (processor == null) {
- // Shouldn't happen, so log a wtf if it does.
- Log.wtf(this, "Received unexpected setSelectedCallServices notification.");
- } else {
- processor.processSelectedCallServices(descriptors);
- }
- }
-
- /**
- * Aborts any ongoing attempts to connect the specified (outgoing) call.
- *
- * @param call The call to be aborted.
- * @return False if the call was not found; True otherwise, indicating that the abort was
- * successful.
- */
- boolean abort(Call call) {
- OutgoingCallProcessor processor = mOutgoingCallProcessors.remove(call);
- if (processor != null) {
- Log.v(this, "abort, call: %s", call);
- processor.abort();
- return true;
- }
-
- return false;
- }
-}
diff --git a/src/com/android/telecomm/ServiceBinder.java b/src/com/android/telecomm/ServiceBinder.java
index ed84bcf..55e39f0 100644
--- a/src/com/android/telecomm/ServiceBinder.java
+++ b/src/com/android/telecomm/ServiceBinder.java
@@ -219,7 +219,7 @@
final boolean isServiceValid(String actionName) {
if (mBinder == null) {
- Log.wtf(this, "%s invoked while service is unbound", actionName);
+ Log.w(this, "%s invoked while service is unbound", actionName);
return false;
}
diff --git a/src/com/android/telecomm/Switchboard.java b/src/com/android/telecomm/Switchboard.java
index 5b8d25d..834bf44 100644
--- a/src/com/android/telecomm/Switchboard.java
+++ b/src/com/android/telecomm/Switchboard.java
@@ -37,89 +37,10 @@
* Switchboard is responsible for:
* - gathering the {@link CallServiceWrapper}s and {@link CallServiceSelectorWrapper}s through
* which to place outgoing calls
- * - starting outgoing calls (via {@link OutgoingCallsManager}
*/
final class Switchboard {
- /**
- * Encapsulates a request to place an outgoing call.
- * TODO(santoscordon): Move this state into Call and remove this class.
- */
- private final class OutgoingCallEntry {
- final Call call;
-
- private Collection<CallServiceWrapper> mCallServices;
- private Collection<CallServiceSelectorWrapper> mSelectors;
- private boolean mIsCallPending = true;
-
- OutgoingCallEntry(Call call) {
- this.call = call;
- }
-
- /**
- * Sets the call services to attempt for this outgoing call.
- *
- * @param callServices The call services.
- */
- void setCallServices(Collection<CallServiceWrapper> callServices) {
- mCallServices = callServices;
- onLookupComplete();
- }
-
- Collection<CallServiceWrapper> getCallServices() {
- return mCallServices;
- }
-
- /**
- * Sets the selectors to attemnpt for this outgoing call.
- *
- * @param selectors The call-service selectors.
- */
- void setSelectors(Collection<CallServiceSelectorWrapper> selectors) {
- mSelectors = selectors;
- onLookupComplete();
- }
-
- Collection<CallServiceSelectorWrapper> getSelectors() {
- return mSelectors;
- }
-
- /** Expires the pending outgoing call and stops it from being made. */
- void expire() {
- // This can be executed in three states:
- // 1) We are still waiting for the list of CSs (Call Services)
- // 2) We told outgoing calls manager to place the call using the CSs
- // 3) Outgoing calls manager already successfully placed the call.
- if (mIsCallPending) {
- // Handle state (1), tell the call to clean itself up and shut everything down.
- mIsCallPending = false;
- call.handleFailedOutgoing(true /* isAborted */);
- } else {
- // Handle states (2) & (3). We can safely call abort() in either case. If the call
- // is not yet successful, then it will abort. If the call was already placed, then
- // outgoing calls manager will do nothing (and return false which we ignore).
- boolean isAborted = mOutgoingCallsManager.abort(call);
- Log.v(this, "expire() caused abort: %b", isAborted);
- }
- }
-
- /** Initiates processing of the call once call-services and selectors are set. */
- private void onLookupComplete() {
- if (mIsCallPending) {
- if (mSelectors != null && mCallServices != null) {
- mIsCallPending = false;
- processNewOutgoingCall(this);
- }
- }
- }
- }
-
- private final static int MSG_EXPIRE_STALE_CALL = 1;
-
private final static Switchboard sInstance = new Switchboard();
- /** Used to place outgoing calls. */
- private final OutgoingCallsManager mOutgoingCallsManager;
-
/** Used to retrieve incoming call details. */
private final IncomingCallsManager mIncomingCallsManager;
@@ -127,20 +48,6 @@
private final CallServiceSelectorRepository mSelectorRepository;
- /** Used to schedule tasks on the main (UI) thread. */
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch(msg.what) {
- case MSG_EXPIRE_STALE_CALL:
- ((OutgoingCallEntry) msg.obj).expire();
- break;
- default:
- Log.wtf(Switchboard.this, "Unexpected message %d.", msg.what);
- }
- }
- };
-
/** Singleton accessor. */
static Switchboard getInstance() {
return sInstance;
@@ -152,41 +59,18 @@
private Switchboard() {
ThreadUtil.checkOnMainThread();
- mOutgoingCallsManager = new OutgoingCallsManager();
mIncomingCallsManager = new IncomingCallsManager();
- mSelectorRepository = new CallServiceSelectorRepository(mOutgoingCallsManager);
+ mSelectorRepository = new CallServiceSelectorRepository();
mCallServiceRepository =
- new CallServiceRepository(mOutgoingCallsManager, mIncomingCallsManager);
+ new CallServiceRepository(mIncomingCallsManager);
}
- /**
- * 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.
- */
- void placeOutgoingCall(Call call) {
- final OutgoingCallEntry callEntry = new OutgoingCallEntry(call);
+ CallServiceRepository getCallServiceRepository() {
+ return mCallServiceRepository;
+ }
- // Lookup call services
- mCallServiceRepository.lookupServices(new LookupCallback<CallServiceWrapper>() {
- @Override
- public void onComplete(Collection<CallServiceWrapper> services) {
- callEntry.setCallServices(services);
- }
- });
-
- // Lookup selectors
- mSelectorRepository.lookupServices(new LookupCallback<CallServiceSelectorWrapper>() {
- @Override
- public void onComplete(Collection<CallServiceSelectorWrapper> selectors) {
- callEntry.setSelectors(selectors);
- }
- });
-
- Message msg = mHandler.obtainMessage(MSG_EXPIRE_STALE_CALL, callEntry);
- mHandler.sendMessageDelayed(msg, Timeouts.getNewOutgoingCallMillis());
+ CallServiceSelectorRepository getSelectorRepository() {
+ return mSelectorRepository;
}
/**
@@ -203,57 +87,4 @@
call.setCallService(callService);
mIncomingCallsManager.retrieveIncomingCall(call, extras);
}
-
- /**
- * Ensures any state regarding a call is cleaned up.
- *
- * @param call The call.
- */
- void abortCall(Call call) {
- Log.d(this, "abortCall");
- mOutgoingCallsManager.abort(call);
- }
-
- /**
- * Attempts to place the specified call.
- *
- * @param callEntry The call entry to place.
- */
- private void processNewOutgoingCall(OutgoingCallEntry callEntry) {
- Collection<CallServiceSelectorWrapper> selectors;
- Call call = callEntry.call;
-
- // Use the call's selector if it's already tied to one. This is the case for handoff calls.
- if (call.getCallServiceSelector() != null) {
- selectors = ImmutableList.of(call.getCallServiceSelector());
- } else {
- selectors = callEntry.getSelectors();
- }
-
- boolean useEmergencySelector =
- EmergencyCallServiceSelector.shouldUseSelector(call.getHandle());
- Log.d(this, "processNewOutgoingCall, isEmergency=%b", useEmergencySelector);
-
- if (useEmergencySelector) {
- // This is potentially an emergency call so add the emergency selector before the
- // other selectors.
- ImmutableList.Builder<CallServiceSelectorWrapper> selectorsBuilder =
- ImmutableList.builder();
-
- ComponentName componentName = new ComponentName(
- TelecommApp.getInstance(), EmergencyCallServiceSelector.class);
- CallServiceSelectorWrapper emergencySelector =
- new CallServiceSelectorWrapper(
- componentName.flattenToShortString(),
- componentName,
- CallsManager.getInstance(),
- mOutgoingCallsManager);
-
- selectorsBuilder.add(emergencySelector);
- selectorsBuilder.addAll(selectors);
- selectors = selectorsBuilder.build();
- }
-
- mOutgoingCallsManager.placeCall(call, callEntry.getCallServices(), selectors);
- }
}