Combining Wrappers and adapters.
Cleaner code this way with fewer indirections. Also maps better to new
Telecomm design.
Change-Id: I88cf8f6382f307a7a2ce86e8acdd614283d1d0a5
diff --git a/src/com/android/telecomm/CallIdMapper.java b/src/com/android/telecomm/CallIdMapper.java
index a5d70bf..7044d89 100644
--- a/src/com/android/telecomm/CallIdMapper.java
+++ b/src/com/android/telecomm/CallIdMapper.java
@@ -65,7 +65,7 @@
if (objId instanceof String) {
callId = (String) objId;
}
- Preconditions.checkArgument(isValidCallId(callId));
+ checkValidCallId(callId);
return mCalls.get(callId);
}
@@ -73,8 +73,8 @@
void checkValidCallId(String callId) {
// Note, no need for thread check, this method is thread safe.
if (!isValidCallId(callId)) {
- Log.wtf(this, "%s is not a valid call ID", callId);
- throw new IllegalArgumentException("Invalid call ID.");
+ throw new IllegalArgumentException(
+ "Invalid call ID for " + mCallIdPrefix + ": " + callId);
}
}
diff --git a/src/com/android/telecomm/CallServiceAdapter.java b/src/com/android/telecomm/CallServiceAdapter.java
deleted file mode 100644
index 39de235..0000000
--- a/src/com/android/telecomm/CallServiceAdapter.java
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Copyright (C) 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.os.Handler;
-import android.os.Message;
-import android.telecomm.CallInfo;
-
-import com.android.internal.telecomm.ICallServiceAdapter;
-import com.google.android.collect.Sets;
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.android.internal.os.SomeArgs;
-
-import java.util.Set;
-
-/**
- * Used by call services to communicate with Telecomm. Each call service is given its own instance
- * of the adapter for the lifetmie of the binding.
- * TODO(santoscordon): Do we need Binder.clear/restoreCallingIdentity() in the service methods?
- */
-public final class CallServiceAdapter 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;
- private static final int MSG_SET_ACTIVE = 4;
- private static final int MSG_SET_RINGING = 5;
- private static final int MSG_SET_DIALING = 6;
- private static final int MSG_SET_DISCONNECTED = 7;
- private static final int MSG_SET_ON_HOLD = 8;
-
- private final class CallServiceAdapterHandler extends Handler {
- @Override
- 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()) {
- CallInfo callInfo = new CallInfo(null, clientCallInfo.getState(),
- clientCallInfo.getHandle());
- mIncomingCallsManager.handleSuccessfulIncomingCall(call, callInfo);
- } else {
- Log.w(this, "notifyIncomingCall, unknown incoming call: %s, id: %s", call,
- 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);
- } else {
- // TODO(gilad): Figure out how to wire up the callService.abort() call.
- Log.w(this,
- "handleSuccessfulOutgoingCall, unknown outgoing call: %s, id: %s",
- call, msg.obj);
- }
- break;
- case MSG_HANDLE_FAILED_OUTGOING_CALL: {
- SomeArgs args = (SomeArgs) msg.obj;
- try {
- call = mCallIdMapper.getCall(args.arg1);
- String reason = (String) args.arg2;
- if (call != null && mPendingCalls.remove(call) && !call.isIncoming()) {
- mOutgoingCallsManager.handleFailedCallAttempt(call, reason);
- } else {
- Log.w(this,
- "handleFailedOutgoingCall, unknown outgoing call: %s, id: %s",
- call, args.arg1);
- }
- } finally {
- args.recycle();
- }
- break;
- }
- case MSG_SET_ACTIVE:
- call = mCallIdMapper.getCall(msg.obj);
- if (call != null) {
- mCallsManager.markCallAsActive(call);
- } else {
- Log.w(this, "setActive, unknown call id: %s", msg.obj);
- }
- break;
- case MSG_SET_RINGING:
- call = mCallIdMapper.getCall(msg.obj);
- if (call != null) {
- mCallsManager.markCallAsRinging(call);
- } else {
- Log.w(this, "setRinging, unknown call id: %s", msg.obj);
- }
- break;
- case MSG_SET_DIALING:
- call = mCallIdMapper.getCall(msg.obj);
- if (call != null) {
- mCallsManager.markCallAsDialing(call);
- } else {
- Log.w(this, "setDialing, unknown call id: %s", msg.obj);
- }
- break;
- case MSG_SET_DISCONNECTED: {
- SomeArgs args = (SomeArgs) msg.obj;
- try {
- call = mCallIdMapper.getCall(args.arg1);
- String disconnectMessage = (String) args.arg2;
- int disconnectCause = args.argi1;
- if (call != null) {
- mCallsManager.markCallAsDisconnected(call, disconnectCause,
- disconnectMessage);
- } else {
- Log.w(this, "setDisconnected, unknown call id: %s", args.arg1);
- }
- } finally {
- args.recycle();
- }
- break;
- }
- case MSG_SET_ON_HOLD:
- call = mCallIdMapper.getCall(msg.obj);
- if (call != null) {
- mCallsManager.markCallAsOnHold(call);
- } else {
- Log.w(this, "setOnHold, unknown call id: %s", msg.obj);
- }
- break;
- }
- }
- }
-
- private final CallsManager mCallsManager;
- private final OutgoingCallsManager mOutgoingCallsManager;
- private final IncomingCallsManager mIncomingCallsManager;
- private final Handler mHandler = new CallServiceAdapterHandler();
- private final CallIdMapper mCallIdMapper;
- private final Set<Call> mPendingCalls = Sets.newHashSet();
-
- /**
- * Persists the specified parameters.
- *
- * @param outgoingCallsManager Manages the placing of outgoing calls.
- * @param incomingCallsManager Manages the incoming call initialization flow.
- */
- CallServiceAdapter(
- OutgoingCallsManager outgoingCallsManager,
- IncomingCallsManager incomingCallsManager,
- CallIdMapper callIdMapper) {
- ThreadUtil.checkOnMainThread();
- mCallsManager = CallsManager.getInstance();
- mOutgoingCallsManager = outgoingCallsManager;
- mIncomingCallsManager = incomingCallsManager;
- mCallIdMapper = callIdMapper;
- }
-
- /** {@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();
- }
-
- /** {@inheritDoc} */
- @Override
- public void notifyIncomingCall(CallInfo callInfo) {
- mCallIdMapper.checkValidCallId(callInfo.getId());
- mHandler.obtainMessage(MSG_NOTIFY_INCOMING_CALL, callInfo).sendToTarget();
- }
-
- /** {@inheritDoc} */
- @Override
- public void handleSuccessfulOutgoingCall(String callId) {
- mCallIdMapper.checkValidCallId(callId);
- mHandler.obtainMessage(MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL, callId).sendToTarget();
- }
-
- /** {@inheritDoc} */
- @Override
- public void handleFailedOutgoingCall(String callId, String reason) {
- mCallIdMapper.checkValidCallId(callId);
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = callId;
- args.arg2 = reason;
- mHandler.obtainMessage(MSG_HANDLE_FAILED_OUTGOING_CALL, args).sendToTarget();
- }
-
- /** {@inheritDoc} */
- @Override
- public void setActive(String callId) {
- mCallIdMapper.checkValidCallId(callId);
- mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
- }
-
- /** {@inheritDoc} */
- @Override
- public void setRinging(String callId) {
- mCallIdMapper.checkValidCallId(callId);
- mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
- }
-
- /** {@inheritDoc} */
- @Override
- public void setDialing(String callId) {
- mCallIdMapper.checkValidCallId(callId);
- mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
- }
-
- /** {@inheritDoc} */
- @Override
- public void setDisconnected(
- String callId, int disconnectCause, String disconnectMessage) {
- mCallIdMapper.checkValidCallId(callId);
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = callId;
- args.arg2 = disconnectMessage;
- args.argi1 = disconnectCause;
- mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
- }
-
- /** {@inheritDoc} */
- @Override
- public void setOnHold(String callId) {
- mCallIdMapper.checkValidCallId(callId);
- mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
- }
-
- /**
- * Adds the specified call to the list of pending calls. Only calls in this list which are
- * outgoing will be handled by {@link #isCompatibleWith}, {@link handleSuccessfulOutgoingCall},
- * and {@link handleFailedOutgoingCall}. Similarly, only calls in this list which are incoming
- * will be handled by {@link notifyIncomingCall}.
- */
- void addPendingCall(Call call) {
- mPendingCalls.add(call);
- }
-
- /**
- * Removes the specified call from the list of pending calls.
- */
- void removePendingCall(Call call) {
- mPendingCalls.remove(call);
- }
-
- /**
- * Called when the associated call service dies.
- */
- void handleCallServiceDeath() {
- if (!mPendingCalls.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.");
- }
- }
-
- if (!mPendingCalls.isEmpty()) {
- Log.wtf(this, "Pending calls did not get cleared.");
- mPendingCalls.clear();
- }
- }
- }
-}
diff --git a/src/com/android/telecomm/CallServiceSelectorAdapter.java b/src/com/android/telecomm/CallServiceSelectorAdapter.java
deleted file mode 100644
index 3fa3b10..0000000
--- a/src/com/android/telecomm/CallServiceSelectorAdapter.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 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.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.telecomm.CallServiceDescriptor;
-
-import com.android.internal.telecomm.ICallServiceSelectorAdapter;
-import com.android.internal.os.SomeArgs;
-
-import java.util.List;
-
-/**
- * Used by call service selector to communicate with Telecomm.
- */
-public final class CallServiceSelectorAdapter extends ICallServiceSelectorAdapter.Stub {
- private static final int MSG_SET_SELECTED_CALL_SERVICES = 0;
- private static final int MSG_CANCEL_OUTGOING_CALL = 1;
- private static final int MSG_SET_HANDOFF_INFO = 2;
-
- private final class CallServiceSelectorAdapterHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- 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);
- } else {
- Log.w(this, "setSelectedCallServices: unknown call: %s, id: %s",
- call, args.arg1);
- }
- } finally {
- args.recycle();
- }
- break;
- }
- case MSG_CANCEL_OUTGOING_CALL: {
- Call call = mCallIdMapper.getCall(msg.obj);
- if (call != null) {
- mOutgoingCallsManager.abort(call);
- } else {
- Log.w(this, "cancelOutgoingCall: unknown call: %s, id: %s", call, msg.obj);
- }
- break;
- }
- case MSG_SET_HANDOFF_INFO: {
- SomeArgs args = (SomeArgs) msg.obj;
- try {
- Call call = mCallIdMapper.getCall(args.arg1);
- Uri handle = (Uri) args.arg2;
- Bundle extras = (Bundle) args.arg3;
- if (call != null) {
- mCallsManager.setHandoffInfo(call, handle, extras);
- } else {
- Log.w(this, "setHandoffInfo: unknown call: %s, id: %s",
- call, args.arg1);
- }
- } finally {
- args.recycle();
- }
- break;
- }
- }
- }
- }
-
- private final Handler mHandler = new CallServiceSelectorAdapterHandler();
- private final CallsManager mCallsManager;
- private final OutgoingCallsManager mOutgoingCallsManager;
- private final CallIdMapper mCallIdMapper;
-
- CallServiceSelectorAdapter(
- CallsManager callsManager,
- OutgoingCallsManager outgoingCallsManager,
- CallIdMapper callIdMapper) {
- ThreadUtil.checkOnMainThread();
- mCallsManager = callsManager;
- mOutgoingCallsManager = outgoingCallsManager;
- mCallIdMapper = callIdMapper;
- }
-
- /**
- * @see CallServiceSelectorAdapter#setSelectedCallServices(String,List<CallServiceDescriptor>)
- */
- @Override
- public void setSelectedCallServices(String callId, List<CallServiceDescriptor> descriptors) {
- mCallIdMapper.checkValidCallId(callId);
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = callId;
- args.arg2 = descriptors;
- mHandler.obtainMessage(MSG_SET_SELECTED_CALL_SERVICES, args).sendToTarget();
- }
-
- /** @see CallServiceSelectorAdapter#cancelOutgoingCall(String) */
- @Override
- public void cancelOutgoingCall(String callId) {
- mCallIdMapper.checkValidCallId(callId);
- mHandler.obtainMessage(MSG_CANCEL_OUTGOING_CALL, callId).sendToTarget();
- }
-
- /** @see CallServiceSelectorAdapter#setHandoffInfo(String,Uri,Bundle) */
- @Override
- public void setHandoffInfo(String callId, Uri handle, Bundle extras) {
- mCallIdMapper.checkValidCallId(callId);
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = callId;
- args.arg2 = handle;
- args.arg3 = extras;
- mHandler.obtainMessage(MSG_SET_HANDOFF_INFO, args).sendToTarget();
- }
-}
diff --git a/src/com/android/telecomm/CallServiceSelectorWrapper.java b/src/com/android/telecomm/CallServiceSelectorWrapper.java
index b5adda0..74073df 100644
--- a/src/com/android/telecomm/CallServiceSelectorWrapper.java
+++ b/src/com/android/telecomm/CallServiceSelectorWrapper.java
@@ -17,13 +17,18 @@
package com.android.telecomm;
import android.content.ComponentName;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Message;
import android.os.RemoteException;
import android.telecomm.CallInfo;
import android.telecomm.CallServiceDescriptor;
-import android.telecomm.CallServiceSelector;
import android.telecomm.TelecommConstants;
+import com.android.internal.os.SomeArgs;
import com.android.internal.telecomm.ICallServiceSelector;
import com.android.internal.telecomm.ICallServiceSelectorAdapter;
@@ -34,10 +39,100 @@
* safely be unbound.
*/
final class CallServiceSelectorWrapper extends ServiceBinder<ICallServiceSelector> {
- private ICallServiceSelector mSelectorInterface;
+
+ private final class Adapter extends ICallServiceSelectorAdapter.Stub {
+ private static final int MSG_SET_SELECTED_CALL_SERVICES = 0;
+ private static final int MSG_CANCEL_OUTGOING_CALL = 1;
+ private static final int MSG_SET_HANDOFF_INFO = 2;
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ 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);
+ } else {
+ Log.w(this, "setSelectedCallServices: unknown call: %s, id: %s",
+ call, args.arg1);
+ }
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case MSG_CANCEL_OUTGOING_CALL: {
+ Call call = mCallIdMapper.getCall(msg.obj);
+ if (call != null) {
+ mOutgoingCallsManager.abort(call);
+ } else {
+ Log.w(this, "cancelOutgoingCall: unknown call: %s, id: %s", call,
+ msg.obj);
+ }
+ break;
+ }
+ case MSG_SET_HANDOFF_INFO: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ Call call = mCallIdMapper.getCall(args.arg1);
+ Uri handle = (Uri) args.arg2;
+ Bundle extras = (Bundle) args.arg3;
+ if (call != null) {
+ mCallsManager.setHandoffInfo(call, handle, extras);
+ } else {
+ Log.w(this, "setHandoffInfo: unknown call: %s, id: %s",
+ call, args.arg1);
+ }
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ }
+ }
+ };
+
+ @Override
+ public void setSelectedCallServices(String callId,
+ List<CallServiceDescriptor> descriptors) {
+ mCallIdMapper.checkValidCallId(callId);
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = descriptors;
+ mHandler.obtainMessage(MSG_SET_SELECTED_CALL_SERVICES, args).sendToTarget();
+ }
+
+ @Override
+ public void cancelOutgoingCall(String callId) {
+ mCallIdMapper.checkValidCallId(callId);
+ mHandler.obtainMessage(MSG_CANCEL_OUTGOING_CALL, callId).sendToTarget();
+ }
+
+ @Override
+ public void setHandoffInfo(String callId, Uri handle, Bundle extras) {
+ mCallIdMapper.checkValidCallId(callId);
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = handle;
+ args.arg3 = extras;
+ mHandler.obtainMessage(MSG_SET_HANDOFF_INFO, args).sendToTarget();
+ }
+ }
+
private final Binder mBinder = new Binder();
private final CallIdMapper mCallIdMapper = new CallIdMapper("CallServiceSelector");
- private final CallServiceSelectorAdapter mAdapter;
+ private final Adapter mAdapter = new Adapter();
+
+ private final CallsManager mCallsManager;
+ private final OutgoingCallsManager mOutgoingCallsManager;
+
+ private ICallServiceSelector mSelectorInterface;
/**
* Creates a call-service selector for the specified component using the specified action to
@@ -55,8 +150,8 @@
OutgoingCallsManager outgoingCallsManager) {
super(action, componentName);
- mAdapter =
- new CallServiceSelectorAdapter(callsManager, outgoingCallsManager, mCallIdMapper);
+ mCallsManager = callsManager;
+ mOutgoingCallsManager = outgoingCallsManager;
}
/**
@@ -78,16 +173,6 @@
outgoingCallsManager);
}
- /** See {@link CallServiceSelector#setCallServiceSelectorAdapter}. */
- private void setCallServiceSelectorAdapter(ICallServiceSelectorAdapter adapter) {
- if (isServiceValid("setCallServiceSelectorAdapter")) {
- try {
- mSelectorInterface.setCallServiceSelectorAdapter(adapter);
- } catch (RemoteException e) {
- }
- }
- }
-
/**
* Retrieves the sorted set of call services that are preferred by this selector. Upon failure,
* the error callback is invoked. Can be invoked even when the call service is unbound.
@@ -120,42 +205,6 @@
mBinder.bind(callback);
}
- private void onCallUpdated(final CallInfo callInfo) {
- BindCallback callback = new BindCallback() {
- @Override
- public void onSuccess() {
- if (isServiceValid("onCallUpdated")) {
- try {
- mSelectorInterface.onCallUpdated(callInfo);
- } catch (RemoteException e) {
- }
- }
- }
- @Override
- public void onFailure() {
- }
- };
- mBinder.bind(callback);
- }
-
- private void onCallRemoved(final String callId) {
- BindCallback callback = new BindCallback() {
- @Override
- public void onSuccess() {
- if (isServiceValid("onCallRemoved")) {
- try {
- mSelectorInterface.onCallRemoved(callId);
- } catch (RemoteException e) {
- }
- }
- }
- @Override
- public void onFailure() {
- }
- };
- mBinder.bind(callback);
- }
-
void addCall(Call call) {
mCallIdMapper.addCall(call);
onCallUpdated(call.toCallInfo(mCallIdMapper.getCallId(call)));
@@ -177,4 +226,51 @@
setCallServiceSelectorAdapter(mAdapter);
}
}
+
+ private void setCallServiceSelectorAdapter(ICallServiceSelectorAdapter adapter) {
+ if (isServiceValid("setCallServiceSelectorAdapter")) {
+ try {
+ mSelectorInterface.setCallServiceSelectorAdapter(adapter);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ private void onCallUpdated(final CallInfo callInfo) {
+ BindCallback callback = new BindCallback() {
+ @Override
+ public void onSuccess() {
+ if (isServiceValid("onCallUpdated")) {
+ try {
+ mSelectorInterface.onCallUpdated(callInfo);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ @Override
+ public void onFailure() {
+ }
+ };
+ mBinder.bind(callback);
+ }
+
+ private void onCallRemoved(final String callId) {
+ BindCallback callback = new BindCallback() {
+ @Override
+ public void onSuccess() {
+ if (isServiceValid("onCallRemoved")) {
+ try {
+ mSelectorInterface.onCallRemoved(callId);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ @Override
+ public void onFailure() {
+ }
+ };
+ mBinder.bind(callback);
+ }
}
diff --git a/src/com/android/telecomm/CallServiceWrapper.java b/src/com/android/telecomm/CallServiceWrapper.java
index 70f0ec2..a4e3d24 100644
--- a/src/com/android/telecomm/CallServiceWrapper.java
+++ b/src/com/android/telecomm/CallServiceWrapper.java
@@ -17,7 +17,10 @@
package com.android.telecomm;
import android.os.Bundle;
+
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Message;
import android.os.RemoteException;
import android.telecomm.CallAudioState;
import android.telecomm.CallInfo;
@@ -25,10 +28,15 @@
import android.telecomm.CallServiceDescriptor;
import android.telecomm.TelecommConstants;
+import com.android.internal.os.SomeArgs;
import com.android.internal.telecomm.ICallService;
import com.android.internal.telecomm.ICallServiceAdapter;
import com.android.internal.telecomm.ICallServiceProvider;
import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
+
+import java.util.Set;
/**
* Wrapper for {@link ICallService}s, handles binding to {@link ICallService} and keeps track of
@@ -37,25 +45,216 @@
*/
final class CallServiceWrapper extends ServiceBinder<ICallService> {
- /** The descriptor of this call service as supplied by the call-service provider. */
+ 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;
+ private static final int MSG_SET_ACTIVE = 4;
+ private static final int MSG_SET_RINGING = 5;
+ private static final int MSG_SET_DIALING = 6;
+ private static final int MSG_SET_DISCONNECTED = 7;
+ private static final int MSG_SET_ON_HOLD = 8;
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ 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()) {
+ CallInfo callInfo = new CallInfo(null, clientCallInfo.getState(),
+ clientCallInfo.getHandle());
+ mIncomingCallsManager.handleSuccessfulIncomingCall(call, callInfo);
+ } else {
+ Log.w(this, "notifyIncomingCall, unknown incoming call: %s, id: %s",
+ call,
+ 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);
+ } 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);
+ }
+ break;
+ case MSG_HANDLE_FAILED_OUTGOING_CALL: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ call = mCallIdMapper.getCall(args.arg1);
+ String reason = (String) args.arg2;
+ if (call != null && mPendingCalls.remove(call) && !call.isIncoming()) {
+ mOutgoingCallsManager.handleFailedCallAttempt(call, reason);
+ } else {
+ Log.w(this,
+ "handleFailedOutgoingCall, unknown call: %s, id: %s",
+ call, args.arg1);
+ }
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case MSG_SET_ACTIVE:
+ call = mCallIdMapper.getCall(msg.obj);
+ if (call != null) {
+ mCallsManager.markCallAsActive(call);
+ } else {
+ Log.w(this, "setActive, unknown call id: %s", msg.obj);
+ }
+ break;
+ case MSG_SET_RINGING:
+ call = mCallIdMapper.getCall(msg.obj);
+ if (call != null) {
+ mCallsManager.markCallAsRinging(call);
+ } else {
+ Log.w(this, "setRinging, unknown call id: %s", msg.obj);
+ }
+ break;
+ case MSG_SET_DIALING:
+ call = mCallIdMapper.getCall(msg.obj);
+ if (call != null) {
+ mCallsManager.markCallAsDialing(call);
+ } else {
+ Log.w(this, "setDialing, unknown call id: %s", msg.obj);
+ }
+ break;
+ case MSG_SET_DISCONNECTED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ call = mCallIdMapper.getCall(args.arg1);
+ String disconnectMessage = (String) args.arg2;
+ int disconnectCause = args.argi1;
+ if (call != null) {
+ mCallsManager.markCallAsDisconnected(call, disconnectCause,
+ disconnectMessage);
+ } else {
+ Log.w(this, "setDisconnected, unknown call id: %s", args.arg1);
+ }
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case MSG_SET_ON_HOLD:
+ call = mCallIdMapper.getCall(msg.obj);
+ if (call != null) {
+ mCallsManager.markCallAsOnHold(call);
+ } else {
+ Log.w(this, "setOnHold, unknown call id: %s", msg.obj);
+ }
+ break;
+ }
+ }
+ };
+
+ /** {@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();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void notifyIncomingCall(CallInfo callInfo) {
+ mCallIdMapper.checkValidCallId(callInfo.getId());
+ mHandler.obtainMessage(MSG_NOTIFY_INCOMING_CALL, callInfo).sendToTarget();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void handleSuccessfulOutgoingCall(String callId) {
+ mCallIdMapper.checkValidCallId(callId);
+ mHandler.obtainMessage(MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL, callId).sendToTarget();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void handleFailedOutgoingCall(String callId, String reason) {
+ mCallIdMapper.checkValidCallId(callId);
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = reason;
+ mHandler.obtainMessage(MSG_HANDLE_FAILED_OUTGOING_CALL, args).sendToTarget();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void setActive(String callId) {
+ mCallIdMapper.checkValidCallId(callId);
+ mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void setRinging(String callId) {
+ mCallIdMapper.checkValidCallId(callId);
+ mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void setDialing(String callId) {
+ mCallIdMapper.checkValidCallId(callId);
+ mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void setDisconnected(
+ String callId, int disconnectCause, String disconnectMessage) {
+ mCallIdMapper.checkValidCallId(callId);
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = disconnectMessage;
+ args.argi1 = disconnectCause;
+ mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void setOnHold(String callId) {
+ mCallIdMapper.checkValidCallId(callId);
+ mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
+ }
+ }
+
+ private final Adapter mAdapter = new Adapter();
+ private final CallsManager mCallsManager = CallsManager.getInstance();
+ private final Set<Call> mPendingCalls = Sets.newHashSet();
private final CallServiceDescriptor mDescriptor;
-
- /**
- * The adapter used by the underlying call-service implementation to communicate with Telecomm.
- */
- private final CallServiceAdapter mAdapter;
-
- /** The actual service implementation. */
- private ICallService mServiceInterface;
+ private final CallIdMapper mCallIdMapper = new CallIdMapper("CallService");
+ private final OutgoingCallsManager mOutgoingCallsManager;
+ private final IncomingCallsManager mIncomingCallsManager;
private Binder mBinder = new Binder();
- private final CallIdMapper mCallIdMapper;
+ private ICallService mServiceInterface;
/**
* Creates a call-service for the specified descriptor.
*
* @param descriptor The call-service descriptor from
- * {@link ICallServiceProvider#lookupCallServices}.
+ * {@link ICallServiceProvider#lookupCallServices}.
* @param outgoingCallsManager Manages the placing of outgoing calls.
* @param incomingCallsManager Manages the incoming call initialization flow.
*/
@@ -65,9 +264,8 @@
IncomingCallsManager incomingCallsManager) {
super(TelecommConstants.ACTION_CALL_SERVICE, descriptor.getServiceComponent());
mDescriptor = descriptor;
- mCallIdMapper = new CallIdMapper("CallService");
- mAdapter = new CallServiceAdapter(outgoingCallsManager, incomingCallsManager,
- mCallIdMapper);
+ mIncomingCallsManager = incomingCallsManager;
+ mOutgoingCallsManager = outgoingCallsManager;
}
CallServiceDescriptor getDescriptor() {
@@ -86,7 +284,7 @@
/**
* 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
+ * 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.
@@ -94,17 +292,20 @@
void isCompatibleWith(final Call call, final Runnable errorCallback) {
Log.d(this, "isCompatibleWith(%s) via %s.", call, getComponentName());
BindCallback callback = new BindCallback() {
- @Override public void onSuccess() {
+ @Override
+ public void onSuccess() {
if (isServiceValid("isCompatibleWith")) {
try {
- mAdapter.addPendingCall(call);
+ mPendingCalls.add(call);
CallInfo callInfo = call.toCallInfo(mCallIdMapper.getCallId(call));
mServiceInterface.isCompatibleWith(callInfo);
} catch (RemoteException e) {
}
}
}
- @Override public void onFailure() {
+
+ @Override
+ public void onFailure() {
errorCallback.run();
}
};
@@ -113,7 +314,7 @@
}
/**
- * Attempts to place the specified call, see {@link ICallService#call}. Upon failure, the
+ * 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) {
@@ -129,7 +330,7 @@
/** @see CallService#abort(String) */
void abort(Call call) {
- mAdapter.removePendingCall(call);
+ mPendingCalls.remove(call);
if (isServiceValid("abort")) {
try {
mServiceInterface.abort(mCallIdMapper.getCallId(call));
@@ -172,8 +373,8 @@
/**
* Starts retrieval of details for an incoming call. Details are returned through the
* call-service adapter using the specified call ID. Upon failure, the specified error callback
- * is invoked. Can be invoked even when the call service is unbound.
- * See {@link ICallService#setIncomingCallId}.
+ * is invoked. Can be invoked even when the call service is unbound. See
+ * {@link ICallService#setIncomingCallId}.
*
* @param call The call used for the incoming call.
* @param extras The {@link CallService}-provided extras which need to be sent back.
@@ -182,9 +383,10 @@
void setIncomingCallId(final Call call, final Bundle extras, final Runnable errorCallback) {
Log.d(this, "setIncomingCall(%s) via %s.", call, getComponentName());
BindCallback callback = new BindCallback() {
- @Override public void onSuccess() {
+ @Override
+ public void onSuccess() {
if (isServiceValid("setIncomingCallId")) {
- mAdapter.addPendingCall(call);
+ mPendingCalls.add(call);
try {
mServiceInterface.setIncomingCallId(mCallIdMapper.getCallId(call),
extras);
@@ -192,7 +394,9 @@
}
}
}
- @Override public void onFailure() {
+
+ @Override
+ public void onFailure() {
errorCallback.run();
}
};
@@ -263,18 +467,19 @@
}
void removeCall(Call call) {
- mAdapter.removePendingCall(call);
+ mPendingCalls.remove(call);
mCallIdMapper.removeCall(call);
}
/** {@inheritDoc} */
- @Override protected void setServiceInterface(IBinder binder) {
+ @Override
+ protected void setServiceInterface(IBinder binder) {
if (binder == null) {
// We have lost our service connection. Notify the world that this call service is done.
// We must notify the adapter before CallsManager. The adapter will force any pending
// outgoing calls to try the next call service. This needs to happen before CallsManager
// tries to clean up any calls still associated with this call service.
- mAdapter.handleCallServiceDeath();
+ handleCallServiceDeath();
CallsManager.getInstance().handleCallServiceDeath(this);
mServiceInterface = null;
} else {
@@ -282,4 +487,27 @@
setCallServiceAdapter(mAdapter);
}
}
+
+ /**
+ * Called when the associated call service dies.
+ */
+ private void handleCallServiceDeath() {
+ if (!mPendingCalls.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.");
+ }
+ }
+
+ if (!mPendingCalls.isEmpty()) {
+ Log.wtf(this, "Pending calls did not get cleared.");
+ mPendingCalls.clear();
+ }
+ }
+ }
}