blob: f61bce9a888d076d03b529ccc9990aaf74db6958 [file] [log] [blame]
Santos Cordon681663d2014-01-30 04:32:15 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Ben Gilad9f2bed32013-12-12 17:43:26 -080017package com.android.telecomm;
18
Santos Cordon681663d2014-01-30 04:32:15 -080019import android.os.Handler;
Sailesh Nepal10ea4602014-04-01 17:23:32 -070020import android.os.Message;
Santos Cordon681663d2014-01-30 04:32:15 -080021import android.telecomm.CallInfo;
Santos Cordon681663d2014-01-30 04:32:15 -080022
Sailesh Nepala439e1b2014-03-11 18:19:58 -070023import com.android.internal.telecomm.ICallServiceAdapter;
Santos Cordon7917d382014-02-14 02:31:18 -080024import com.google.android.collect.Sets;
Santos Cordon681663d2014-01-30 04:32:15 -080025import com.google.common.base.Strings;
Santos Cordon4b2c1192014-03-19 18:15:38 -070026import com.google.common.collect.ImmutableList;
Sailesh Nepal10ea4602014-04-01 17:23:32 -070027import com.android.internal.os.SomeArgs;
Santos Cordon681663d2014-01-30 04:32:15 -080028
Santos Cordon7917d382014-02-14 02:31:18 -080029import java.util.Set;
30
Ben Gilad9f2bed32013-12-12 17:43:26 -080031/**
Santos Cordon681663d2014-01-30 04:32:15 -080032 * Used by call services in order to update state and control calls while the call service is bound
33 * to Telecomm. Each call service is given its own instance for the lifetime of the binding between
34 * Telecomm and the call service.
35 * TODO(santoscordon): Whenever we get any method invocations from the call service, we need to
36 * check that the invocation is expected from that call service.
Santos Cordon63aeb162014-02-10 09:20:40 -080037 * TODO(santoscordon): Do we need Binder.clear/restoreCallingIdentity() in the service methods?
Ben Gilad9f2bed32013-12-12 17:43:26 -080038 */
Santos Cordon681663d2014-01-30 04:32:15 -080039public final class CallServiceAdapter extends ICallServiceAdapter.Stub {
Sailesh Nepal10ea4602014-04-01 17:23:32 -070040 private static final int MSG_SET_IS_COMPATIBLE_WITH = 0;
41 private static final int MSG_NOTIFY_INCOMING_CALL = 1;
42 private static final int MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL = 2;
43 private static final int MSG_HANDLE_FAILED_OUTGOING_CALL = 3;
44 private static final int MSG_SET_ACTIVE = 4;
45 private static final int MSG_SET_RINGING = 5;
46 private static final int MSG_SET_DIALING = 6;
47 private static final int MSG_SET_DISCONNECTED = 7;
48 private static final int MSG_SET_ON_HOLD = 8;
49
50 private final class CallServiceAdapterHandler extends Handler {
51 @Override
52 public void handleMessage(Message msg) {
53 String callId;
54
55 switch (msg.what) {
56 case MSG_SET_IS_COMPATIBLE_WITH:
57 callId = (String) msg.obj;
58 if (mPendingOutgoingCallIds.contains(callId)) {
59 mOutgoingCallsManager.setIsCompatibleWith(callId,
60 msg.arg1 == 1 ? true : false);
61 } else {
62 Log.wtf(this, "Unknown outgoing call: %s", callId);
63 }
64 break;
65 case MSG_NOTIFY_INCOMING_CALL:
66 CallInfo callInfo = (CallInfo) msg.obj;
67 if (mPendingIncomingCallIds.remove(callInfo.getId())) {
68 mIncomingCallsManager.handleSuccessfulIncomingCall(callInfo);
69 } else {
70 Log.wtf(this, "Unknown incoming call: %s", callInfo);
71 }
72 break;
73 case MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL:
74 callId = (String) msg.obj;
75 if (mPendingOutgoingCallIds.remove(callId)) {
76 mOutgoingCallsManager.handleSuccessfulCallAttempt(callId);
77 } else {
78 // TODO(gilad): Figure out how to wire up the callService.abort() call.
79 Log.wtf(this, "Unknown outgoing call: %s", callId);
80 }
81 break;
82 case MSG_HANDLE_FAILED_OUTGOING_CALL: {
83 SomeArgs args = (SomeArgs) msg.obj;
84 try {
85 callId = (String) args.arg1;
86 String reason = (String) args.arg2;
87 if (mPendingOutgoingCallIds.remove(callId)) {
88 mOutgoingCallsManager.handleFailedCallAttempt(callId, reason);
89 } else {
90 Log.wtf(this, "Unknown outgoing call: %s", callId);
91 }
92 } finally {
93 args.recycle();
94 }
95 break;
96 }
97 case MSG_SET_ACTIVE:
98 callId = (String) msg.obj;
99 mCallsManager.markCallAsActive(callId);
100 break;
101 case MSG_SET_RINGING:
102 callId = (String) msg.obj;
103 mCallsManager.markCallAsRinging(callId);
104 break;
105 case MSG_SET_DIALING:
106 callId = (String) msg.obj;
107 mCallsManager.markCallAsDialing(callId);
108 break;
109 case MSG_SET_DISCONNECTED: {
110 SomeArgs args = (SomeArgs) msg.obj;
111 try {
112 callId = (String) args.arg1;
113 String disconnectMessage = (String) args.arg2;
114 int disconnectCause = args.argi1;
115 mCallsManager.markCallAsDisconnected(callId, disconnectCause,
116 disconnectMessage);
117 } finally {
118 args.recycle();
119 }
120 break;
121 }
122 case MSG_SET_ON_HOLD:
123 callId = (String) msg.obj;
124 mCallsManager.markCallAsOnHold(callId);
125 break;
126 }
127 }
128 }
129
Santos Cordon681663d2014-01-30 04:32:15 -0800130 private final CallsManager mCallsManager;
Santos Cordon681663d2014-01-30 04:32:15 -0800131 private final OutgoingCallsManager mOutgoingCallsManager;
Santos Cordon493e8f22014-02-19 03:15:12 -0800132 private final IncomingCallsManager mIncomingCallsManager;
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700133 private final Handler mHandler = new CallServiceAdapterHandler();
Santos Cordon681663d2014-01-30 04:32:15 -0800134
Ben Gilad28e8ad62014-03-06 17:01:54 -0800135 /**
136 * The set of pending outgoing call IDs. Any {@link #handleSuccessfulOutgoingCall} and
137 * {@link #handleFailedOutgoingCall} invocations with a call ID that is not in this set
138 * are ignored.
139 */
140 private final Set<String> mPendingOutgoingCallIds = Sets.newHashSet();
141
142 /**
143 * The set of pending incoming call IDs. Any {@link #handleIncomingCall} invocations with
144 * a call ID not in this set are ignored.
Santos Cordon7917d382014-02-14 02:31:18 -0800145 */
Santos Cordon61d0f702014-02-19 02:52:23 -0800146 private final Set<String> mPendingIncomingCallIds = Sets.newHashSet();
Santos Cordon7917d382014-02-14 02:31:18 -0800147
Santos Cordon681663d2014-01-30 04:32:15 -0800148 /**
149 * Persists the specified parameters.
Santos Cordon493e8f22014-02-19 03:15:12 -0800150 *
151 * @param outgoingCallsManager Manages the placing of outgoing calls.
152 * @param incomingCallsManager Manages the incoming call initialization flow.
Santos Cordon681663d2014-01-30 04:32:15 -0800153 */
Santos Cordon493e8f22014-02-19 03:15:12 -0800154 CallServiceAdapter(
155 OutgoingCallsManager outgoingCallsManager, IncomingCallsManager incomingCallsManager) {
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700156 ThreadUtil.checkOnMainThread();
Santos Cordon681663d2014-01-30 04:32:15 -0800157 mCallsManager = CallsManager.getInstance();
158 mOutgoingCallsManager = outgoingCallsManager;
Santos Cordon493e8f22014-02-19 03:15:12 -0800159 mIncomingCallsManager = incomingCallsManager;
Santos Cordon681663d2014-01-30 04:32:15 -0800160 }
161
162 /** {@inheritDoc} */
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700163 @Override
164 public void setIsCompatibleWith(String callId, boolean isCompatible) {
Ben Gilad61925612014-03-11 19:06:36 -0700165 checkValidCallId(callId);
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700166 mHandler.obtainMessage(MSG_SET_IS_COMPATIBLE_WITH, isCompatible ? 1 : 0, 0, callId).
167 sendToTarget();
Santos Cordon681663d2014-01-30 04:32:15 -0800168 }
169
Santos Cordon7917d382014-02-14 02:31:18 -0800170 /** {@inheritDoc} */
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700171 @Override
172 public void notifyIncomingCall(CallInfo callInfo) {
Santos Cordon7917d382014-02-14 02:31:18 -0800173 checkValidCallId(callInfo.getId());
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700174 mHandler.obtainMessage(MSG_NOTIFY_INCOMING_CALL, callInfo).sendToTarget();
Santos Cordon681663d2014-01-30 04:32:15 -0800175 }
176
177 /** {@inheritDoc} */
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700178 @Override
179 public void handleSuccessfulOutgoingCall(String callId) {
Santos Cordon681663d2014-01-30 04:32:15 -0800180 checkValidCallId(callId);
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700181 mHandler.obtainMessage(MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL, callId).sendToTarget();
Santos Cordon681663d2014-01-30 04:32:15 -0800182 }
183
184 /** {@inheritDoc} */
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700185 @Override
186 public void handleFailedOutgoingCall(String callId, String reason) {
Santos Cordon681663d2014-01-30 04:32:15 -0800187 checkValidCallId(callId);
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700188 SomeArgs args = SomeArgs.obtain();
189 args.arg1 = callId;
190 args.arg2 = reason;
191 mHandler.obtainMessage(MSG_HANDLE_FAILED_OUTGOING_CALL, args).sendToTarget();
Santos Cordon681663d2014-01-30 04:32:15 -0800192 }
193
194 /** {@inheritDoc} */
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700195 @Override
196 public void setActive(String callId) {
Santos Cordon681663d2014-01-30 04:32:15 -0800197 checkValidCallId(callId);
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700198 mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
Santos Cordon681663d2014-01-30 04:32:15 -0800199 }
200
201 /** {@inheritDoc} */
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700202 @Override
203 public void setRinging(String callId) {
Santos Cordon681663d2014-01-30 04:32:15 -0800204 checkValidCallId(callId);
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700205 mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
Santos Cordon681663d2014-01-30 04:32:15 -0800206 }
207
208 /** {@inheritDoc} */
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700209 @Override
210 public void setDialing(String callId) {
Santos Cordon681663d2014-01-30 04:32:15 -0800211 checkValidCallId(callId);
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700212 mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
Santos Cordon681663d2014-01-30 04:32:15 -0800213 }
214
215 /** {@inheritDoc} */
Ben Gilad28e8ad62014-03-06 17:01:54 -0800216 // TODO(gilad): Ensure that any communication from the underlying ICallService
217 // implementation is expected (or otherwise suppressed at the adapter level).
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700218 @Override
219 public void setDisconnected(
220 String callId, int disconnectCause, String disconnectMessage) {
Santos Cordon681663d2014-01-30 04:32:15 -0800221 checkValidCallId(callId);
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700222 SomeArgs args = SomeArgs.obtain();
223 args.arg1 = callId;
224 args.arg2 = disconnectMessage;
225 args.argi1 = disconnectCause;
226 mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
Santos Cordon681663d2014-01-30 04:32:15 -0800227 }
228
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700229 /** {@inheritDoc} */
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700230 @Override
231 public void setOnHold(String callId) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700232 checkValidCallId(callId);
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700233 mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700234 }
235
Santos Cordon681663d2014-01-30 04:32:15 -0800236 /**
Ben Gilad28e8ad62014-03-06 17:01:54 -0800237 * Adds the specified call ID to the list of pending outgoing call IDs.
238 * TODO(gilad): Consider passing the call processor (instead of the ID) both here and in the
239 * remove case (same for incoming) such that the detour via the *CallsManager can be avoided.
240 *
241 * @param callId The ID of the call.
242 */
243 void addPendingOutgoingCallId(String callId) {
244 mPendingOutgoingCallIds.add(callId);
245 }
246
247 /**
248 * Removes the specified call ID from the list of pending outgoing call IDs.
249 *
250 * @param callId The ID of the call.
251 */
252 void removePendingOutgoingCallId(String callId) {
253 mPendingOutgoingCallIds.remove(callId);
254 }
255
256 /**
Santos Cordon61d0f702014-02-19 02:52:23 -0800257 * Adds a call ID to the list of pending incoming call IDs. Only calls with call IDs in the
258 * list will be handled by {@link #handleIncomingCall}.
Santos Cordon7917d382014-02-14 02:31:18 -0800259 *
260 * @param callId The ID of the call.
261 */
Santos Cordon61d0f702014-02-19 02:52:23 -0800262 void addPendingIncomingCallId(String callId) {
263 mPendingIncomingCallIds.add(callId);
Santos Cordon7917d382014-02-14 02:31:18 -0800264 }
265
266 /**
Ben Gilad28e8ad62014-03-06 17:01:54 -0800267 * Removes the specified call ID from the list of pending incoming call IDs.
Santos Cordon7917d382014-02-14 02:31:18 -0800268 *
269 * @param callId The ID of the call.
270 */
Santos Cordon61d0f702014-02-19 02:52:23 -0800271 void removePendingIncomingCallId(String callId) {
272 mPendingIncomingCallIds.remove(callId);
Santos Cordon7917d382014-02-14 02:31:18 -0800273 }
274
275 /**
Santos Cordon4b2c1192014-03-19 18:15:38 -0700276 * Called when the associated call service dies.
277 */
278 void handleCallServiceDeath() {
279 if (!mPendingIncomingCallIds.isEmpty()) {
280 // Here and in the for loop below, we need to iterate through a copy because the code
281 // inside the loop will modify the original list.
282 for (String callId : ImmutableList.copyOf(mPendingIncomingCallIds)) {
283 mIncomingCallsManager.handleFailedIncomingCall(callId);
284 }
285
286 if (!mPendingIncomingCallIds.isEmpty()) {
287 Log.wtf(this, "Pending incoming calls did not get cleared.");
288 mPendingIncomingCallIds.clear();
289 }
290 }
291
292 if (!mPendingOutgoingCallIds.isEmpty()) {
293 for (String callId : ImmutableList.copyOf(mPendingOutgoingCallIds)) {
294 mOutgoingCallsManager.handleFailedCallAttempt(callId, "Call service disconnected.");
295 }
296
297 if (!mPendingOutgoingCallIds.isEmpty()) {
298 Log.wtf(this, "Pending outgoing calls did not get cleared.");
299 mPendingOutgoingCallIds.clear();
300 }
301 }
302 }
303
304 /**
Santos Cordon681663d2014-01-30 04:32:15 -0800305 * Throws an IllegalArgumentException if the specified call ID is invalid.
306 *
307 * @param callId The call ID to check.
308 */
309 private void checkValidCallId(String callId) {
310 if (Strings.isNullOrEmpty(callId)) {
Santos Cordon7917d382014-02-14 02:31:18 -0800311 throw new IllegalArgumentException("Invalid call ID.");
Santos Cordon681663d2014-01-30 04:32:15 -0800312 }
313 }
Ben Gilad9f2bed32013-12-12 17:43:26 -0800314}