blob: 7b1fc3e13b48bb2ff3e5142f444b79bd4c5cf3e0 [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;
20import android.os.Looper;
21import 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;
Santos Cordon681663d2014-01-30 04:32:15 -080027
Santos Cordon4b2c1192014-03-19 18:15:38 -070028import java.util.Collections;
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.
37 * TODO(santoscordon): Move away from Runnable objects and into messages so that we create fewer
38 * objects per IPC method call.
Santos Cordon63aeb162014-02-10 09:20:40 -080039 * TODO(santoscordon): Do we need Binder.clear/restoreCallingIdentity() in the service methods?
Ben Gilad9f2bed32013-12-12 17:43:26 -080040 */
Santos Cordon681663d2014-01-30 04:32:15 -080041public final class CallServiceAdapter extends ICallServiceAdapter.Stub {
Santos Cordon681663d2014-01-30 04:32:15 -080042 private final CallsManager mCallsManager;
Ben Gilad9f2bed32013-12-12 17:43:26 -080043
Santos Cordon681663d2014-01-30 04:32:15 -080044 private final OutgoingCallsManager mOutgoingCallsManager;
45
Santos Cordon493e8f22014-02-19 03:15:12 -080046 private final IncomingCallsManager mIncomingCallsManager;
47
Santos Cordon681663d2014-01-30 04:32:15 -080048 /** Used to run code (e.g. messages, Runnables) on the main (UI) thread. */
49 private final Handler mHandler = new Handler(Looper.getMainLooper());
50
Ben Gilad28e8ad62014-03-06 17:01:54 -080051 /**
52 * The set of pending outgoing call IDs. Any {@link #handleSuccessfulOutgoingCall} and
53 * {@link #handleFailedOutgoingCall} invocations with a call ID that is not in this set
54 * are ignored.
55 */
56 private final Set<String> mPendingOutgoingCallIds = Sets.newHashSet();
57
58 /**
59 * The set of pending incoming call IDs. Any {@link #handleIncomingCall} invocations with
60 * a call ID not in this set are ignored.
Santos Cordon7917d382014-02-14 02:31:18 -080061 */
Santos Cordon61d0f702014-02-19 02:52:23 -080062 private final Set<String> mPendingIncomingCallIds = Sets.newHashSet();
Santos Cordon7917d382014-02-14 02:31:18 -080063
Santos Cordon681663d2014-01-30 04:32:15 -080064 /**
65 * Persists the specified parameters.
Santos Cordon493e8f22014-02-19 03:15:12 -080066 *
67 * @param outgoingCallsManager Manages the placing of outgoing calls.
68 * @param incomingCallsManager Manages the incoming call initialization flow.
Santos Cordon681663d2014-01-30 04:32:15 -080069 */
Santos Cordon493e8f22014-02-19 03:15:12 -080070 CallServiceAdapter(
71 OutgoingCallsManager outgoingCallsManager, IncomingCallsManager incomingCallsManager) {
72
Santos Cordon681663d2014-01-30 04:32:15 -080073 mCallsManager = CallsManager.getInstance();
74 mOutgoingCallsManager = outgoingCallsManager;
Santos Cordon493e8f22014-02-19 03:15:12 -080075 mIncomingCallsManager = incomingCallsManager;
Santos Cordon681663d2014-01-30 04:32:15 -080076 }
77
78 /** {@inheritDoc} */
Ben Gilad61925612014-03-11 19:06:36 -070079 @Override public void setIsCompatibleWith(final String callId, final boolean isCompatible) {
80 checkValidCallId(callId);
81 mHandler.post(new Runnable() {
82 @Override public void run() {
83 if (mPendingOutgoingCallIds.contains(callId)) {
84 mOutgoingCallsManager.setIsCompatibleWith(callId, isCompatible);
85 } else {
86 Log.wtf(CallServiceAdapter.this, "Unknown outgoing call: %s", callId);
87 }
88 }
89 });
Santos Cordon681663d2014-01-30 04:32:15 -080090 }
91
Santos Cordon7917d382014-02-14 02:31:18 -080092 /** {@inheritDoc} */
Sailesh Nepala439e1b2014-03-11 18:19:58 -070093 @Override public void notifyIncomingCall(final CallInfo callInfo) {
Santos Cordon7917d382014-02-14 02:31:18 -080094 checkValidCallId(callInfo.getId());
95 mHandler.post(new Runnable() {
96 @Override public void run() {
Santos Cordon61d0f702014-02-19 02:52:23 -080097 if (mPendingIncomingCallIds.remove(callInfo.getId())) {
Santos Cordon493e8f22014-02-19 03:15:12 -080098 mIncomingCallsManager.handleSuccessfulIncomingCall(callInfo);
Santos Cordon7917d382014-02-14 02:31:18 -080099 } else {
Ben Gilad61925612014-03-11 19:06:36 -0700100 Log.wtf(CallServiceAdapter.this, "Unknown incoming call: %s", callInfo);
Santos Cordon7917d382014-02-14 02:31:18 -0800101 }
102 }
103 });
Santos Cordon681663d2014-01-30 04:32:15 -0800104 }
105
106 /** {@inheritDoc} */
107 @Override public void handleSuccessfulOutgoingCall(final String callId) {
108 checkValidCallId(callId);
109 mHandler.post(new Runnable() {
110 @Override public void run() {
Ben Gilad28e8ad62014-03-06 17:01:54 -0800111 if (mPendingOutgoingCallIds.remove(callId)) {
112 mOutgoingCallsManager.handleSuccessfulCallAttempt(callId);
113 } else {
114 // TODO(gilad): Figure out how to wire up the callService.abort() call.
Ben Gilad61925612014-03-11 19:06:36 -0700115 Log.wtf(CallServiceAdapter.this, "Unknown outgoing call: %s", callId);
Ben Gilad28e8ad62014-03-06 17:01:54 -0800116 }
Santos Cordon681663d2014-01-30 04:32:15 -0800117 }
118 });
119 }
120
121 /** {@inheritDoc} */
122 @Override public void handleFailedOutgoingCall(final String callId, final String reason) {
123 checkValidCallId(callId);
124 mHandler.post(new Runnable() {
125 @Override public void run() {
Ben Gilad28e8ad62014-03-06 17:01:54 -0800126 if (mPendingOutgoingCallIds.remove(callId)) {
127 mOutgoingCallsManager.handleFailedCallAttempt(callId, reason);
128 } else {
Ben Gilad61925612014-03-11 19:06:36 -0700129 Log.wtf(CallServiceAdapter.this, "Unknown outgoing call: %s", callId);
Ben Gilad28e8ad62014-03-06 17:01:54 -0800130 }
Santos Cordon681663d2014-01-30 04:32:15 -0800131 }
132 });
133 }
134
135 /** {@inheritDoc} */
136 @Override public void setActive(final String callId) {
137 checkValidCallId(callId);
138 mHandler.post(new Runnable() {
139 @Override public void run() {
140 mCallsManager.markCallAsActive(callId);
141 }
142 });
143 }
144
145 /** {@inheritDoc} */
146 @Override public void setRinging(final String callId) {
147 checkValidCallId(callId);
148 mHandler.post(new Runnable() {
149 @Override public void run() {
150 mCallsManager.markCallAsRinging(callId);
151 }
152 });
153 }
154
155 /** {@inheritDoc} */
156 @Override public void setDialing(final String callId) {
157 checkValidCallId(callId);
158 mHandler.post(new Runnable() {
159 @Override public void run() {
160 mCallsManager.markCallAsDialing(callId);
161 }
162 });
163 }
164
165 /** {@inheritDoc} */
Ben Gilad28e8ad62014-03-06 17:01:54 -0800166 // TODO(gilad): Ensure that any communication from the underlying ICallService
167 // implementation is expected (or otherwise suppressed at the adapter level).
Santos Cordon79ff2bc2014-03-27 15:31:27 -0700168 @Override public void setDisconnected(
169 final String callId, final int disconnectCause, final String disconnectMessage) {
Santos Cordon681663d2014-01-30 04:32:15 -0800170 checkValidCallId(callId);
171 mHandler.post(new Runnable() {
172 @Override public void run() {
Santos Cordon79ff2bc2014-03-27 15:31:27 -0700173 mCallsManager.markCallAsDisconnected(callId, disconnectCause, disconnectMessage);
Santos Cordon681663d2014-01-30 04:32:15 -0800174 }
175 });
176 }
177
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700178 /** {@inheritDoc} */
179 @Override public void setOnHold(final String callId) {
180 checkValidCallId(callId);
181 mHandler.post(new Runnable() {
182 @Override public void run() {
183 mCallsManager.markCallAsOnHold(callId);
184 }
185 });
186 }
187
Santos Cordon681663d2014-01-30 04:32:15 -0800188 /**
Ben Gilad28e8ad62014-03-06 17:01:54 -0800189 * Adds the specified call ID to the list of pending outgoing call IDs.
190 * TODO(gilad): Consider passing the call processor (instead of the ID) both here and in the
191 * remove case (same for incoming) such that the detour via the *CallsManager can be avoided.
192 *
193 * @param callId The ID of the call.
194 */
195 void addPendingOutgoingCallId(String callId) {
196 mPendingOutgoingCallIds.add(callId);
197 }
198
199 /**
200 * Removes the specified call ID from the list of pending outgoing call IDs.
201 *
202 * @param callId The ID of the call.
203 */
204 void removePendingOutgoingCallId(String callId) {
205 mPendingOutgoingCallIds.remove(callId);
206 }
207
208 /**
Santos Cordon61d0f702014-02-19 02:52:23 -0800209 * Adds a call ID to the list of pending incoming call IDs. Only calls with call IDs in the
210 * list will be handled by {@link #handleIncomingCall}.
Santos Cordon7917d382014-02-14 02:31:18 -0800211 *
212 * @param callId The ID of the call.
213 */
Santos Cordon61d0f702014-02-19 02:52:23 -0800214 void addPendingIncomingCallId(String callId) {
215 mPendingIncomingCallIds.add(callId);
Santos Cordon7917d382014-02-14 02:31:18 -0800216 }
217
218 /**
Ben Gilad28e8ad62014-03-06 17:01:54 -0800219 * Removes the specified call ID from the list of pending incoming call IDs.
Santos Cordon7917d382014-02-14 02:31:18 -0800220 *
221 * @param callId The ID of the call.
222 */
Santos Cordon61d0f702014-02-19 02:52:23 -0800223 void removePendingIncomingCallId(String callId) {
224 mPendingIncomingCallIds.remove(callId);
Santos Cordon7917d382014-02-14 02:31:18 -0800225 }
226
227 /**
Santos Cordon4b2c1192014-03-19 18:15:38 -0700228 * Called when the associated call service dies.
229 */
230 void handleCallServiceDeath() {
231 if (!mPendingIncomingCallIds.isEmpty()) {
232 // Here and in the for loop below, we need to iterate through a copy because the code
233 // inside the loop will modify the original list.
234 for (String callId : ImmutableList.copyOf(mPendingIncomingCallIds)) {
235 mIncomingCallsManager.handleFailedIncomingCall(callId);
236 }
237
238 if (!mPendingIncomingCallIds.isEmpty()) {
239 Log.wtf(this, "Pending incoming calls did not get cleared.");
240 mPendingIncomingCallIds.clear();
241 }
242 }
243
244 if (!mPendingOutgoingCallIds.isEmpty()) {
245 for (String callId : ImmutableList.copyOf(mPendingOutgoingCallIds)) {
246 mOutgoingCallsManager.handleFailedCallAttempt(callId, "Call service disconnected.");
247 }
248
249 if (!mPendingOutgoingCallIds.isEmpty()) {
250 Log.wtf(this, "Pending outgoing calls did not get cleared.");
251 mPendingOutgoingCallIds.clear();
252 }
253 }
254 }
255
256 /**
Santos Cordon681663d2014-01-30 04:32:15 -0800257 * Throws an IllegalArgumentException if the specified call ID is invalid.
258 *
259 * @param callId The call ID to check.
260 */
261 private void checkValidCallId(String callId) {
262 if (Strings.isNullOrEmpty(callId)) {
Santos Cordon7917d382014-02-14 02:31:18 -0800263 throw new IllegalArgumentException("Invalid call ID.");
Santos Cordon681663d2014-01-30 04:32:15 -0800264 }
265 }
Ben Gilad9f2bed32013-12-12 17:43:26 -0800266}