blob: 4bd774322db1a7c970f66c6a270de2971332ef98 [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/**
Sailesh Nepale59bb192014-04-01 18:33:59 -070032 * Used by call services to communicate with Telecomm. Each call service is given its own instance
33 * of the adapter for the lifetmie of the binding.
Santos Cordon63aeb162014-02-10 09:20:40 -080034 * TODO(santoscordon): Do we need Binder.clear/restoreCallingIdentity() in the service methods?
Ben Gilad9f2bed32013-12-12 17:43:26 -080035 */
Santos Cordon681663d2014-01-30 04:32:15 -080036public final class CallServiceAdapter extends ICallServiceAdapter.Stub {
Sailesh Nepal10ea4602014-04-01 17:23:32 -070037 private static final int MSG_SET_IS_COMPATIBLE_WITH = 0;
38 private static final int MSG_NOTIFY_INCOMING_CALL = 1;
39 private static final int MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL = 2;
40 private static final int MSG_HANDLE_FAILED_OUTGOING_CALL = 3;
41 private static final int MSG_SET_ACTIVE = 4;
42 private static final int MSG_SET_RINGING = 5;
43 private static final int MSG_SET_DIALING = 6;
44 private static final int MSG_SET_DISCONNECTED = 7;
45 private static final int MSG_SET_ON_HOLD = 8;
46
47 private final class CallServiceAdapterHandler extends Handler {
48 @Override
49 public void handleMessage(Message msg) {
Sailesh Nepale59bb192014-04-01 18:33:59 -070050 Call call;
Sailesh Nepal10ea4602014-04-01 17:23:32 -070051 switch (msg.what) {
52 case MSG_SET_IS_COMPATIBLE_WITH:
Sailesh Nepale59bb192014-04-01 18:33:59 -070053 call = mCallIdMapper.getCall(msg.obj);
54 if (call != null && !call.isIncoming()) {
55 mOutgoingCallsManager.setIsCompatibleWith(call,
Sailesh Nepal10ea4602014-04-01 17:23:32 -070056 msg.arg1 == 1 ? true : false);
57 } else {
Sailesh Nepale59bb192014-04-01 18:33:59 -070058 Log.w(this, "Unknown call: %s, id: %s", call, msg.obj);
Sailesh Nepal10ea4602014-04-01 17:23:32 -070059 }
60 break;
61 case MSG_NOTIFY_INCOMING_CALL:
Sailesh Nepale59bb192014-04-01 18:33:59 -070062 CallInfo clientCallInfo = (CallInfo) msg.obj;
63 call = mCallIdMapper.getCall(clientCallInfo.getId());
64 if (call != null && mPendingCalls.remove(call) && call.isIncoming()) {
65 CallInfo callInfo = new CallInfo(null, clientCallInfo.getState(),
66 clientCallInfo.getHandle());
67 mIncomingCallsManager.handleSuccessfulIncomingCall(call, callInfo);
Sailesh Nepal10ea4602014-04-01 17:23:32 -070068 } else {
Sailesh Nepale59bb192014-04-01 18:33:59 -070069 Log.w(this, "Unknown incoming call: %s, id: %s", call, msg.obj);
Sailesh Nepal10ea4602014-04-01 17:23:32 -070070 }
71 break;
72 case MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL:
Sailesh Nepale59bb192014-04-01 18:33:59 -070073 call = mCallIdMapper.getCall(msg.obj);
74 if (call != null && mPendingCalls.remove(call) && !call.isIncoming()) {
75 mOutgoingCallsManager.handleSuccessfulCallAttempt(call);
Sailesh Nepal10ea4602014-04-01 17:23:32 -070076 } else {
77 // TODO(gilad): Figure out how to wire up the callService.abort() call.
Sailesh Nepale59bb192014-04-01 18:33:59 -070078 Log.w(this, "Unknown outgoing call: %s, id: %s", call, msg.obj);
Sailesh Nepal10ea4602014-04-01 17:23:32 -070079 }
80 break;
81 case MSG_HANDLE_FAILED_OUTGOING_CALL: {
82 SomeArgs args = (SomeArgs) msg.obj;
83 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -070084 call = mCallIdMapper.getCall(args.arg1);
Sailesh Nepal10ea4602014-04-01 17:23:32 -070085 String reason = (String) args.arg2;
Sailesh Nepale59bb192014-04-01 18:33:59 -070086 if (call != null && mPendingCalls.remove(call) && !call.isIncoming()) {
87 mOutgoingCallsManager.handleFailedCallAttempt(call, reason);
Sailesh Nepal10ea4602014-04-01 17:23:32 -070088 } else {
Sailesh Nepale59bb192014-04-01 18:33:59 -070089 Log.w(this, "Unknown outgoing call: %s, id: %s", call, msg.obj);
Sailesh Nepal10ea4602014-04-01 17:23:32 -070090 }
91 } finally {
92 args.recycle();
93 }
94 break;
95 }
96 case MSG_SET_ACTIVE:
Sailesh Nepale59bb192014-04-01 18:33:59 -070097 call = mCallIdMapper.getCall(msg.obj);
98 if (call != null) {
99 mCallsManager.markCallAsActive(call);
100 } else {
101 Log.w(this, "Unknown call id: %s", msg.obj);
102 }
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700103 break;
104 case MSG_SET_RINGING:
Sailesh Nepale59bb192014-04-01 18:33:59 -0700105 call = mCallIdMapper.getCall(msg.obj);
106 if (call != null) {
107 mCallsManager.markCallAsRinging(call);
108 } else {
109 Log.w(this, "Unknown call id: %s", msg.obj);
110 }
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700111 break;
112 case MSG_SET_DIALING:
Sailesh Nepale59bb192014-04-01 18:33:59 -0700113 call = mCallIdMapper.getCall(msg.obj);
114 if (call != null) {
115 mCallsManager.markCallAsDialing(call);
116 } else {
117 Log.w(this, "Unknown call id: %s", msg.obj);
118 }
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700119 break;
120 case MSG_SET_DISCONNECTED: {
121 SomeArgs args = (SomeArgs) msg.obj;
122 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700123 call = mCallIdMapper.getCall(args.arg1);
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700124 String disconnectMessage = (String) args.arg2;
125 int disconnectCause = args.argi1;
Sailesh Nepale59bb192014-04-01 18:33:59 -0700126 if (call != null) {
127 mCallsManager.markCallAsDisconnected(call, disconnectCause,
128 disconnectMessage);
129 } else {
130 Log.w(this, "Unknown call id: %s", msg.obj);
131 }
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700132 } finally {
133 args.recycle();
134 }
135 break;
136 }
137 case MSG_SET_ON_HOLD:
Sailesh Nepale59bb192014-04-01 18:33:59 -0700138 call = mCallIdMapper.getCall(msg.obj);
139 if (call != null) {
140 mCallsManager.markCallAsOnHold(call);
141 } else {
142 Log.w(this, "Unknown call id: %s", msg.obj);
143 }
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700144 break;
145 }
146 }
147 }
148
Santos Cordon681663d2014-01-30 04:32:15 -0800149 private final CallsManager mCallsManager;
Santos Cordon681663d2014-01-30 04:32:15 -0800150 private final OutgoingCallsManager mOutgoingCallsManager;
Santos Cordon493e8f22014-02-19 03:15:12 -0800151 private final IncomingCallsManager mIncomingCallsManager;
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700152 private final Handler mHandler = new CallServiceAdapterHandler();
Sailesh Nepale59bb192014-04-01 18:33:59 -0700153 private final CallIdMapper mCallIdMapper;
154 private final Set<Call> mPendingCalls = Sets.newHashSet();
Santos Cordon7917d382014-02-14 02:31:18 -0800155
Santos Cordon681663d2014-01-30 04:32:15 -0800156 /**
157 * Persists the specified parameters.
Santos Cordon493e8f22014-02-19 03:15:12 -0800158 *
159 * @param outgoingCallsManager Manages the placing of outgoing calls.
160 * @param incomingCallsManager Manages the incoming call initialization flow.
Santos Cordon681663d2014-01-30 04:32:15 -0800161 */
Santos Cordon493e8f22014-02-19 03:15:12 -0800162 CallServiceAdapter(
Sailesh Nepale59bb192014-04-01 18:33:59 -0700163 OutgoingCallsManager outgoingCallsManager,
164 IncomingCallsManager incomingCallsManager,
165 CallIdMapper callIdMapper) {
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700166 ThreadUtil.checkOnMainThread();
Santos Cordon681663d2014-01-30 04:32:15 -0800167 mCallsManager = CallsManager.getInstance();
168 mOutgoingCallsManager = outgoingCallsManager;
Santos Cordon493e8f22014-02-19 03:15:12 -0800169 mIncomingCallsManager = incomingCallsManager;
Sailesh Nepale59bb192014-04-01 18:33:59 -0700170 mCallIdMapper = callIdMapper;
Santos Cordon681663d2014-01-30 04:32:15 -0800171 }
172
173 /** {@inheritDoc} */
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700174 @Override
175 public void setIsCompatibleWith(String callId, boolean isCompatible) {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700176 Log.v(this, "setIsCompatibleWith id: %d, isCompatible: %b", callId, isCompatible);
177 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700178 mHandler.obtainMessage(MSG_SET_IS_COMPATIBLE_WITH, isCompatible ? 1 : 0, 0, callId).
179 sendToTarget();
Santos Cordon681663d2014-01-30 04:32:15 -0800180 }
181
Santos Cordon7917d382014-02-14 02:31:18 -0800182 /** {@inheritDoc} */
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700183 @Override
184 public void notifyIncomingCall(CallInfo callInfo) {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700185 mCallIdMapper.checkValidCallId(callInfo.getId());
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700186 mHandler.obtainMessage(MSG_NOTIFY_INCOMING_CALL, callInfo).sendToTarget();
Santos Cordon681663d2014-01-30 04:32:15 -0800187 }
188
189 /** {@inheritDoc} */
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700190 @Override
191 public void handleSuccessfulOutgoingCall(String callId) {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700192 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700193 mHandler.obtainMessage(MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL, callId).sendToTarget();
Santos Cordon681663d2014-01-30 04:32:15 -0800194 }
195
196 /** {@inheritDoc} */
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700197 @Override
198 public void handleFailedOutgoingCall(String callId, String reason) {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700199 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700200 SomeArgs args = SomeArgs.obtain();
201 args.arg1 = callId;
202 args.arg2 = reason;
203 mHandler.obtainMessage(MSG_HANDLE_FAILED_OUTGOING_CALL, args).sendToTarget();
Santos Cordon681663d2014-01-30 04:32:15 -0800204 }
205
206 /** {@inheritDoc} */
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700207 @Override
208 public void setActive(String callId) {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700209 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700210 mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
Santos Cordon681663d2014-01-30 04:32:15 -0800211 }
212
213 /** {@inheritDoc} */
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700214 @Override
215 public void setRinging(String callId) {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700216 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700217 mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
Santos Cordon681663d2014-01-30 04:32:15 -0800218 }
219
220 /** {@inheritDoc} */
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700221 @Override
222 public void setDialing(String callId) {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700223 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700224 mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
Santos Cordon681663d2014-01-30 04:32:15 -0800225 }
226
227 /** {@inheritDoc} */
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700228 @Override
229 public void setDisconnected(
230 String callId, int disconnectCause, String disconnectMessage) {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700231 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700232 SomeArgs args = SomeArgs.obtain();
233 args.arg1 = callId;
234 args.arg2 = disconnectMessage;
235 args.argi1 = disconnectCause;
236 mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
Santos Cordon681663d2014-01-30 04:32:15 -0800237 }
238
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700239 /** {@inheritDoc} */
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700240 @Override
241 public void setOnHold(String callId) {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700242 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepal10ea4602014-04-01 17:23:32 -0700243 mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700244 }
245
Santos Cordon681663d2014-01-30 04:32:15 -0800246 /**
Sailesh Nepale59bb192014-04-01 18:33:59 -0700247 * Adds the specified call to the list of pending calls. Only calls in this list which are
248 * outgoing will be handled by {@link #isCompatibleWith}, {@link handleSuccessfulOutgoingCall},
249 * and {@link handleFailedOutgoingCall}. Similarly, only calls in this list which are incoming
250 * will be handled by {@link notifyIncomingCall}.
Ben Gilad28e8ad62014-03-06 17:01:54 -0800251 */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700252 void addPendingCall(Call call) {
253 mPendingCalls.add(call);
Ben Gilad28e8ad62014-03-06 17:01:54 -0800254 }
255
256 /**
Sailesh Nepale59bb192014-04-01 18:33:59 -0700257 * Removes the specified call from the list of pending calls.
Ben Gilad28e8ad62014-03-06 17:01:54 -0800258 */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700259 void removePendingCall(Call call) {
260 mPendingCalls.remove(call);
Santos Cordon7917d382014-02-14 02:31:18 -0800261 }
262
263 /**
Santos Cordon4b2c1192014-03-19 18:15:38 -0700264 * Called when the associated call service dies.
265 */
266 void handleCallServiceDeath() {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700267 if (!mPendingCalls.isEmpty()) {
268 // Iterate through a copy because the code inside the loop will modify the original
269 // list.
270 for (Call call : ImmutableList.copyOf(mPendingCalls)) {
271 if (call.isIncoming()) {
272 mIncomingCallsManager.handleFailedIncomingCall(call);
273 } else {
274 mOutgoingCallsManager.handleFailedCallAttempt(call,
275 "Call service disconnected.");
276 }
Santos Cordon4b2c1192014-03-19 18:15:38 -0700277 }
278
Sailesh Nepale59bb192014-04-01 18:33:59 -0700279 if (!mPendingCalls.isEmpty()) {
280 Log.wtf(this, "Pending calls did not get cleared.");
281 mPendingCalls.clear();
Santos Cordon4b2c1192014-03-19 18:15:38 -0700282 }
283 }
Santos Cordon681663d2014-01-30 04:32:15 -0800284 }
Ben Gilad9f2bed32013-12-12 17:43:26 -0800285}