blob: f95953a722678841d9fb7cbf69f00162fad4ecd8 [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 Cordon681663d2014-01-30 04:32:15 -0800168 @Override public void setDisconnected(final String callId) {
169 checkValidCallId(callId);
170 mHandler.post(new Runnable() {
171 @Override public void run() {
172 mCallsManager.markCallAsDisconnected(callId);
173 }
174 });
175 }
176
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700177 /** {@inheritDoc} */
178 @Override public void setOnHold(final String callId) {
179 checkValidCallId(callId);
180 mHandler.post(new Runnable() {
181 @Override public void run() {
182 mCallsManager.markCallAsOnHold(callId);
183 }
184 });
185 }
186
Santos Cordon681663d2014-01-30 04:32:15 -0800187 /**
Ben Gilad28e8ad62014-03-06 17:01:54 -0800188 * Adds the specified call ID to the list of pending outgoing call IDs.
189 * TODO(gilad): Consider passing the call processor (instead of the ID) both here and in the
190 * remove case (same for incoming) such that the detour via the *CallsManager can be avoided.
191 *
192 * @param callId The ID of the call.
193 */
194 void addPendingOutgoingCallId(String callId) {
195 mPendingOutgoingCallIds.add(callId);
196 }
197
198 /**
199 * Removes the specified call ID from the list of pending outgoing call IDs.
200 *
201 * @param callId The ID of the call.
202 */
203 void removePendingOutgoingCallId(String callId) {
204 mPendingOutgoingCallIds.remove(callId);
205 }
206
207 /**
Santos Cordon61d0f702014-02-19 02:52:23 -0800208 * Adds a call ID to the list of pending incoming call IDs. Only calls with call IDs in the
209 * list will be handled by {@link #handleIncomingCall}.
Santos Cordon7917d382014-02-14 02:31:18 -0800210 *
211 * @param callId The ID of the call.
212 */
Santos Cordon61d0f702014-02-19 02:52:23 -0800213 void addPendingIncomingCallId(String callId) {
214 mPendingIncomingCallIds.add(callId);
Santos Cordon7917d382014-02-14 02:31:18 -0800215 }
216
217 /**
Ben Gilad28e8ad62014-03-06 17:01:54 -0800218 * Removes the specified call ID from the list of pending incoming call IDs.
Santos Cordon7917d382014-02-14 02:31:18 -0800219 *
220 * @param callId The ID of the call.
221 */
Santos Cordon61d0f702014-02-19 02:52:23 -0800222 void removePendingIncomingCallId(String callId) {
223 mPendingIncomingCallIds.remove(callId);
Santos Cordon7917d382014-02-14 02:31:18 -0800224 }
225
226 /**
Santos Cordon4b2c1192014-03-19 18:15:38 -0700227 * Called when the associated call service dies.
228 */
229 void handleCallServiceDeath() {
230 if (!mPendingIncomingCallIds.isEmpty()) {
231 // Here and in the for loop below, we need to iterate through a copy because the code
232 // inside the loop will modify the original list.
233 for (String callId : ImmutableList.copyOf(mPendingIncomingCallIds)) {
234 mIncomingCallsManager.handleFailedIncomingCall(callId);
235 }
236
237 if (!mPendingIncomingCallIds.isEmpty()) {
238 Log.wtf(this, "Pending incoming calls did not get cleared.");
239 mPendingIncomingCallIds.clear();
240 }
241 }
242
243 if (!mPendingOutgoingCallIds.isEmpty()) {
244 for (String callId : ImmutableList.copyOf(mPendingOutgoingCallIds)) {
245 mOutgoingCallsManager.handleFailedCallAttempt(callId, "Call service disconnected.");
246 }
247
248 if (!mPendingOutgoingCallIds.isEmpty()) {
249 Log.wtf(this, "Pending outgoing calls did not get cleared.");
250 mPendingOutgoingCallIds.clear();
251 }
252 }
253 }
254
255 /**
Santos Cordon681663d2014-01-30 04:32:15 -0800256 * Throws an IllegalArgumentException if the specified call ID is invalid.
257 *
258 * @param callId The call ID to check.
259 */
260 private void checkValidCallId(String callId) {
261 if (Strings.isNullOrEmpty(callId)) {
Santos Cordon7917d382014-02-14 02:31:18 -0800262 throw new IllegalArgumentException("Invalid call ID.");
Santos Cordon681663d2014-01-30 04:32:15 -0800263 }
264 }
Ben Gilad9f2bed32013-12-12 17:43:26 -0800265}