blob: 0722ec646bf799bdef782fe4159a7d959e68fda0 [file] [log] [blame]
Santos Cordon63aeb162014-02-10 09:20:40 -08001/*
2 * Copyright 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
17package com.android.telecomm;
18
Evan Charltona05805b2014-03-05 08:21:46 -080019import android.os.Bundle;
Santos Cordon63aeb162014-02-10 09:20:40 -080020import android.os.IBinder;
21import android.os.RemoteException;
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070022import android.telecomm.CallAudioState;
Santos Cordon63aeb162014-02-10 09:20:40 -080023import android.telecomm.CallInfo;
Evan Charltona05805b2014-03-05 08:21:46 -080024import android.telecomm.CallService;
Ben Giladc5b22692014-02-18 20:03:22 -080025import android.telecomm.CallServiceDescriptor;
Sailesh Nepal83cfe7c2014-03-11 19:54:22 -070026import android.telecomm.TelecommConstants;
Sailesh Nepala439e1b2014-03-11 18:19:58 -070027
28import com.android.internal.telecomm.ICallService;
29import com.android.internal.telecomm.ICallServiceAdapter;
30import com.android.internal.telecomm.ICallServiceProvider;
Santos Cordon63aeb162014-02-10 09:20:40 -080031
32/**
33 * Wrapper for {@link ICallService}s, handles binding to {@link ICallService} and keeps track of
34 * when the object can safely be unbound. Other classes should not use {@link ICallService} directly
35 * and instead should use this class to invoke methods of {@link ICallService}.
Santos Cordon63aeb162014-02-10 09:20:40 -080036 */
Ben Gilad61925612014-03-11 19:06:36 -070037final class CallServiceWrapper extends ServiceBinder<ICallService> {
Santos Cordon63aeb162014-02-10 09:20:40 -080038
Santos Cordonc195e362014-02-11 17:05:31 -080039 /** The descriptor of this call service as supplied by the call-service provider. */
Ben Giladc5b22692014-02-18 20:03:22 -080040 private final CallServiceDescriptor mDescriptor;
Santos Cordonc195e362014-02-11 17:05:31 -080041
42 /**
43 * The adapter used by the underlying call-service implementation to communicate with Telecomm.
44 */
45 private final CallServiceAdapter mAdapter;
46
47 /** The actual service implementation. */
48 private ICallService mServiceInterface;
49
Ben Gilad61925612014-03-11 19:06:36 -070050 private Binder mBinder = new Binder();
51
Santos Cordon63aeb162014-02-10 09:20:40 -080052 /**
Sailesh Nepal18386a82014-03-19 10:22:40 -070053 * Creates a call-service provider for the specified descriptor.
Santos Cordonc195e362014-02-11 17:05:31 -080054 *
Santos Cordon61d0f702014-02-19 02:52:23 -080055 * @param descriptor The call-service descriptor from
56 * {@link ICallServiceProvider#lookupCallServices}.
Santos Cordonc195e362014-02-11 17:05:31 -080057 * @param adapter The call-service adapter.
Santos Cordon63aeb162014-02-10 09:20:40 -080058 */
Ben Gilad61925612014-03-11 19:06:36 -070059 CallServiceWrapper(CallServiceDescriptor descriptor, CallServiceAdapter adapter) {
Sailesh Nepala439e1b2014-03-11 18:19:58 -070060 super(TelecommConstants.ACTION_CALL_SERVICE, descriptor.getServiceComponent());
Ben Giladc5b22692014-02-18 20:03:22 -080061 mDescriptor = descriptor;
Santos Cordonc195e362014-02-11 17:05:31 -080062 mAdapter = adapter;
Santos Cordon63aeb162014-02-10 09:20:40 -080063 }
64
Ben Gilad61925612014-03-11 19:06:36 -070065 CallServiceDescriptor getDescriptor() {
Ben Giladc5b22692014-02-18 20:03:22 -080066 return mDescriptor;
Santos Cordonc195e362014-02-11 17:05:31 -080067 }
68
Santos Cordon63aeb162014-02-10 09:20:40 -080069 /** See {@link ICallService#setCallServiceAdapter}. */
Ben Gilad61925612014-03-11 19:06:36 -070070 void setCallServiceAdapter(ICallServiceAdapter callServiceAdapter) {
Santos Cordon61d0f702014-02-19 02:52:23 -080071 if (isServiceValid("setCallServiceAdapter")) {
72 try {
Santos Cordon63aeb162014-02-10 09:20:40 -080073 mServiceInterface.setCallServiceAdapter(callServiceAdapter);
Santos Cordon61d0f702014-02-19 02:52:23 -080074 } catch (RemoteException e) {
Sailesh Nepalf1c191d2014-03-07 18:17:39 -080075 Log.e(this, e, "Failed to setCallServiceAdapter.");
Santos Cordon63aeb162014-02-10 09:20:40 -080076 }
Santos Cordon63aeb162014-02-10 09:20:40 -080077 }
78 }
79
Ben Gilad61925612014-03-11 19:06:36 -070080 /**
81 * Checks whether or not the specified call is compatible with this call-service implementation,
82 * see {@link ICallService#isCompatibleWith}. Upon failure, the specified error callback is
83 * invoked. Can be invoked even when the call service is unbound.
84 *
85 * @param callInfo The details of the call.
86 * @param errorCallback The callback to invoke upon failure.
87 */
88 void isCompatibleWith(final CallInfo callInfo, final Runnable errorCallback) {
Santos Cordon4b2c1192014-03-19 18:15:38 -070089 Log.d(this, "isCompatibleWith(%s) via %s.", callInfo, getComponentName());
Ben Gilad61925612014-03-11 19:06:36 -070090 BindCallback callback = new BindCallback() {
91 @Override public void onSuccess() {
92 if (isServiceValid("isCompatibleWith")) {
93 try {
Yorke Leeadee12d2014-03-13 12:08:30 -070094 mAdapter.addPendingOutgoingCallId(callInfo.getId());
Ben Gilad61925612014-03-11 19:06:36 -070095 mServiceInterface.isCompatibleWith(callInfo);
96 } catch (RemoteException e) {
Yorke Leeadee12d2014-03-13 12:08:30 -070097 mAdapter.removePendingOutgoingCallId(callInfo.getId());
Ben Gilad61925612014-03-11 19:06:36 -070098 Log.e(CallServiceWrapper.this, e, "Failed checking isCompatibleWith.");
99 }
100 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800101 }
Ben Gilad61925612014-03-11 19:06:36 -0700102 @Override public void onFailure() {
103 errorCallback.run();
104 }
105 };
106
107 mBinder.bind(callback);
Santos Cordon63aeb162014-02-10 09:20:40 -0800108 }
109
Ben Gilad61925612014-03-11 19:06:36 -0700110 /**
111 * Attempts to place the specified call, see {@link ICallService#call}. Upon failure, the
112 * specified error callback is invoked. Can be invoked even when the call service is unbound.
113 *
114 * @param callInfo The details of the call.
115 * @param errorCallback The callback to invoke upon failure.
116 */
117 void call(final CallInfo callInfo, final Runnable errorCallback) {
Santos Cordon4b2c1192014-03-19 18:15:38 -0700118 Log.d(this, "call(%s) via %s.", callInfo, getComponentName());
Ben Gilad61925612014-03-11 19:06:36 -0700119 BindCallback callback = new BindCallback() {
120 @Override public void onSuccess() {
121 String callId = callInfo.getId();
122 if (isServiceValid("call")) {
123 try {
124 mServiceInterface.call(callInfo);
Ben Gilad61925612014-03-11 19:06:36 -0700125 } catch (RemoteException e) {
126 Log.e(CallServiceWrapper.this, e, "Failed to place call %s", callId);
127 }
128 }
Ben Gilad28e8ad62014-03-06 17:01:54 -0800129 }
Ben Gilad61925612014-03-11 19:06:36 -0700130 @Override public void onFailure() {
131 errorCallback.run();
132 }
133 };
134
135 mBinder.bind(callback);
Ben Gilad28e8ad62014-03-06 17:01:54 -0800136 }
137
138 /** See {@link ICallService#abort}. */
Ben Gilad61925612014-03-11 19:06:36 -0700139 void abort(String callId) {
Ben Gilad28e8ad62014-03-06 17:01:54 -0800140 mAdapter.removePendingOutgoingCallId(callId);
141 if (isServiceValid("abort")) {
142 try {
143 mServiceInterface.abort(callId);
144 } catch (RemoteException e) {
145 Log.e(this, e, "Failed to abort call %s", callId);
Santos Cordon63aeb162014-02-10 09:20:40 -0800146 }
Santos Cordon61d0f702014-02-19 02:52:23 -0800147 }
148 }
149
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700150 /** See {@link ICallService#hold}. */
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700151 void hold(String callId) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700152 if (isServiceValid("hold")) {
153 try {
154 mServiceInterface.hold(callId);
155 } catch (RemoteException e) {
156 Log.e(this, e, "Failed to put on hold for call %s", callId);
157 }
158 }
159 }
160
161 /** See {@link ICallService#unhold}. */
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700162 void unhold(String callId) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700163 if (isServiceValid("unhold")) {
164 try {
165 mServiceInterface.unhold(callId);
166 } catch (RemoteException e) {
167 Log.e(this, e, "Failed to remove from hold for call %s", callId);
168 }
169 }
170 }
171
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700172 /** See {@link ICallService#onAudioStateChanged}. */
173 void onAudioStateChanged(String activeCallId, CallAudioState audioState) {
174 if (isServiceValid("onAudioStateChanged")) {
175 try {
176 mServiceInterface.onAudioStateChanged(activeCallId, audioState);
177 } catch (RemoteException e) {
178 Log.e(this, e, "Failed to update audio state for call %s", activeCallId);
179 }
180 }
181 }
182
Ben Gilad61925612014-03-11 19:06:36 -0700183 /**
184 * Starts retrieval of details for an incoming call. Details are returned through the
185 * call-service adapter using the specified call ID. Upon failure, the specified error callback
186 * is invoked. Can be invoked even when the call service is unbound.
187 * See {@link ICallService#setIncomingCallId}.
188 *
189 * @param callId The call ID used for the incoming call.
190 * @param extras The {@link CallService}-provided extras which need to be sent back.
191 * @param errorCallback The callback to invoke upon failure.
192 */
193 void setIncomingCallId(
194 final String callId,
195 final Bundle extras,
196 final Runnable errorCallback) {
197
Santos Cordon4b2c1192014-03-19 18:15:38 -0700198 Log.d(this, "setIncomingCall(%s) via %s.", callId, getComponentName());
Ben Gilad61925612014-03-11 19:06:36 -0700199 BindCallback callback = new BindCallback() {
200 @Override public void onSuccess() {
201 if (isServiceValid("setIncomingCallId")) {
202 mAdapter.addPendingIncomingCallId(callId);
203 try {
204 mServiceInterface.setIncomingCallId(callId, extras);
205 } catch (RemoteException e) {
206 Log.e(CallServiceWrapper.this, e,
207 "Failed to setIncomingCallId for call %s", callId);
208 mAdapter.removePendingIncomingCallId(callId);
209 }
210 }
Santos Cordon61d0f702014-02-19 02:52:23 -0800211 }
Ben Gilad61925612014-03-11 19:06:36 -0700212 @Override public void onFailure() {
213 errorCallback.run();
214 }
215 };
216
217 mBinder.bind(callback);
Santos Cordon63aeb162014-02-10 09:20:40 -0800218 }
219
220 /** See {@link ICallService#disconnect}. */
Ben Gilad61925612014-03-11 19:06:36 -0700221 void disconnect(String callId) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800222 if (isServiceValid("disconnect")) {
223 try {
Santos Cordon63aeb162014-02-10 09:20:40 -0800224 mServiceInterface.disconnect(callId);
Santos Cordon61d0f702014-02-19 02:52:23 -0800225 } catch (RemoteException e) {
Sailesh Nepalf1c191d2014-03-07 18:17:39 -0800226 Log.e(this, e, "Failed to disconnect call %s", callId);
Santos Cordon63aeb162014-02-10 09:20:40 -0800227 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800228 }
229 }
Santos Cordon5c12c6e2014-02-13 14:35:31 -0800230
Santos Cordon61d0f702014-02-19 02:52:23 -0800231 /** See {@link ICallService#answer}. */
Ben Gilad61925612014-03-11 19:06:36 -0700232 void answer(String callId) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800233 if (isServiceValid("answer")) {
234 try {
235 mServiceInterface.answer(callId);
236 } catch (RemoteException e) {
Sailesh Nepalf1c191d2014-03-07 18:17:39 -0800237 Log.e(this, e, "Failed to answer call %s", callId);
Santos Cordon7917d382014-02-14 02:31:18 -0800238 }
Santos Cordon61d0f702014-02-19 02:52:23 -0800239 }
240 }
241
242 /** See {@link ICallService#reject}. */
Ben Gilad61925612014-03-11 19:06:36 -0700243 void reject(String callId) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800244 if (isServiceValid("reject")) {
245 try {
246 mServiceInterface.reject(callId);
247 } catch (RemoteException e) {
Sailesh Nepalf1c191d2014-03-07 18:17:39 -0800248 Log.e(this, e, "Failed to reject call %s");
Santos Cordon61d0f702014-02-19 02:52:23 -0800249 }
Santos Cordon7917d382014-02-14 02:31:18 -0800250 }
251 }
252
253 /**
Santos Cordon61d0f702014-02-19 02:52:23 -0800254 * Cancels the incoming call for the specified call ID.
255 * TODO(santoscordon): This method should be called by IncomingCallsManager when the incoming
256 * call has failed.
Santos Cordon7917d382014-02-14 02:31:18 -0800257 *
258 * @param callId The ID of the call.
259 */
260 void cancelIncomingCall(String callId) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800261 mAdapter.removePendingIncomingCallId(callId);
Santos Cordon7917d382014-02-14 02:31:18 -0800262 }
263
Yorke Leeadee12d2014-03-13 12:08:30 -0700264 /**
265 * Cancels the outgoing call for the specified call ID.
266 *
267 * @param callId The ID of the call.
268 */
269 void cancelOutgoingCall(String callId) {
270 mAdapter.removePendingOutgoingCallId(callId);
271 }
272
Santos Cordon5c12c6e2014-02-13 14:35:31 -0800273 /** {@inheritDoc} */
274 @Override protected void setServiceInterface(IBinder binder) {
Santos Cordon4b2c1192014-03-19 18:15:38 -0700275 if (binder == null) {
276 // We have lost our service connection. Notify the world that this call service is done.
277 // We must notify the adapter before CallsManager. The adapter will force any pending
278 // outgoing calls to try the next call service. This needs to happen before CallsManager
279 // tries to clean up any calls still associated with this call service.
280 mAdapter.handleCallServiceDeath();
281 CallsManager.getInstance().handleCallServiceDeath(this);
282 mServiceInterface = null;
283 } else {
284 mServiceInterface = ICallService.Stub.asInterface(binder);
285 setCallServiceAdapter(mAdapter);
286 }
Santos Cordon5c12c6e2014-02-13 14:35:31 -0800287 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800288}