blob: 02a100ec4a84fc760dcde109ff1c256253c99b7d [file] [log] [blame]
Santos Cordon52d8a152014-06-17 19:08:45 -07001/*
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 R* limitations under the License.
15 */
16
17package android.telecomm;
18
19import android.content.ComponentName;
20import android.net.Uri;
21import android.os.IBinder.DeathRecipient;
22import android.os.RemoteException;
23import android.telephony.DisconnectCause;
24
25import android.text.TextUtils;
26
27import com.android.internal.telecomm.ICallService;
28import com.android.internal.telecomm.ICallServiceAdapter;
Andrew Lee5ffbe8b2014-06-20 16:29:33 -070029import com.android.internal.telecomm.ICallVideoProvider;
Santos Cordon52d8a152014-06-17 19:08:45 -070030import com.android.internal.telecomm.RemoteServiceCallback;
31
32import java.util.ArrayList;
33import java.util.Collections;
34import java.util.LinkedList;
35import java.util.List;
36import java.util.UUID;
37
38/**
39 * Remote connection service which other connection services can use to place calls on their behalf.
Sailesh Nepal091768c2014-06-30 15:15:23 -070040 *
41 * @hide
Santos Cordon52d8a152014-06-17 19:08:45 -070042 */
Sailesh Nepal091768c2014-06-30 15:15:23 -070043public final class RemoteConnectionService implements DeathRecipient {
Santos Cordon52d8a152014-06-17 19:08:45 -070044 private final ICallService mCallService;
45 private final ComponentName mComponentName;
46
47 private String mConnectionId;
48 private ConnectionRequest mPendingRequest;
Sailesh Nepal506e3862014-06-25 13:35:14 -070049 private ConnectionService.OutgoingCallResponse<RemoteConnection> mPendingOutgoingCallResponse;
Santos Cordon52d8a152014-06-17 19:08:45 -070050 // Remote connection services only support a single connection.
51 private RemoteConnection mConnection;
52
53 private final ICallServiceAdapter mAdapter = new ICallServiceAdapter.Stub() {
54
55 /** ${inheritDoc} */
56 @Override
57 public void notifyIncomingCall(CallInfo callInfo) {
58 Log.w(this, "notifyIncomingCall not implemented in Remote connection");
59 }
60
61 /** ${inheritDoc} */
62 @Override
63 public void handleSuccessfulOutgoingCall(String connectionId) {
64 if (isPendingConnection(connectionId)) {
65 mConnection = new RemoteConnection(mCallService, connectionId);
Sailesh Nepal506e3862014-06-25 13:35:14 -070066 mPendingOutgoingCallResponse.onSuccess(mPendingRequest, mConnection);
Santos Cordon52d8a152014-06-17 19:08:45 -070067 clearPendingInformation();
68 }
69 }
70
71 /** ${inheritDoc} */
72 @Override
73 public void handleFailedOutgoingCall(
74 ConnectionRequest request, int errorCode, String errorMessage) {
75 if (isPendingConnection(request.getCallId())) {
Sailesh Nepal091768c2014-06-30 15:15:23 -070076 mPendingOutgoingCallResponse.onFailure(request, errorCode, errorMessage);
Sailesh Nepal506e3862014-06-25 13:35:14 -070077 mConnectionId = null;
78 clearPendingInformation();
79 }
80 }
81
82 /** ${inheritDoc} */
83 @Override
84 public void cancelOutgoingCall(String connectionId) {
85 if (isPendingConnection(connectionId)) {
86 mPendingOutgoingCallResponse.onCancel(mPendingRequest);
Santos Cordon52d8a152014-06-17 19:08:45 -070087 mConnectionId = null;
88 clearPendingInformation();
89 }
90 }
91
92 /** ${inheritDoc} */
93 @Override
94 public void setActive(String connectionId) {
95 if (isCurrentConnection(connectionId)) {
96 mConnection.setState(Connection.State.ACTIVE);
97 }
98 }
99
100 /** ${inheritDoc} */
101 @Override
102 public void setRinging(String connectionId) {
103 if (isCurrentConnection(connectionId)) {
104 mConnection.setState(Connection.State.RINGING);
105 }
106 }
107
108 /** ${inheritDoc} */
Andrew Lee5ffbe8b2014-06-20 16:29:33 -0700109 public void setCallVideoProvider(
110 String connectionId, ICallVideoProvider callVideoProvider) {
111 // not supported for remote connections.
112 }
113
114 /** ${inheritDoc} */
Santos Cordon52d8a152014-06-17 19:08:45 -0700115 @Override
116 public void setDialing(String connectionId) {
117 if (isCurrentConnection(connectionId)) {
118 mConnection.setState(Connection.State.DIALING);
119 }
120 }
121
122 /** ${inheritDoc} */
123 @Override
124 public void setDisconnected(
125 String connectionId, int disconnectCause, String disconnectMessage) {
126 if (isCurrentConnection(connectionId)) {
127 mConnection.setDisconnected(disconnectCause, disconnectMessage);
128 }
129 }
130
131 /** ${inheritDoc} */
132 @Override
133 public void setOnHold(String connectionId) {
134 if (isCurrentConnection(connectionId)) {
135 mConnection.setState(Connection.State.HOLDING);
136 }
137 }
138
139 /** ${inheritDoc} */
140 @Override
141 public void setRequestingRingback(String connectionId, boolean isRequestingRingback) {
142 if (isCurrentConnection(connectionId)) {
143 mConnection.setRequestingRingback(isRequestingRingback);
144 }
145 }
146
147 /** ${inheritDoc} */
148 @Override
149 public void setCanConference(String connectionId, boolean canConference) {
150 // not supported for remote connections.
151 }
152
153 /** ${inheritDoc} */
154 @Override
155 public void setIsConferenced(String connectionId, String conferenceConnectionId) {
156 // not supported for remote connections.
157 }
158
159 /** ${inheritDoc} */
160 @Override
161 public void addConferenceCall(String connectionId, CallInfo callInfo) {
162 // not supported for remote connections.
163 }
164
165 /** ${inheritDoc} */
166 @Override
167 public void removeCall(String connectionId) {
168 if (isCurrentConnection(connectionId)) {
169 destroyConnection();
170 }
171 }
172
173 /** ${inheritDoc} */
174 @Override
175 public void onPostDialWait(String connectionId, String remainingDigits) {
176 if (isCurrentConnection(connectionId)) {
177 mConnection.setPostDialWait(remainingDigits);
178 }
179 }
180
181 /** ${inheritDoc} */
182 @Override
183 public void handoffCall(String connectionId) {
184 // unnecessary.
185 }
186
187 /** ${inheritDoc} */
188 @Override
189 public void queryRemoteConnectionServices(RemoteServiceCallback callback) {
190 try {
191 // Not supported from remote connection service.
192 callback.onError();
193 } catch (RemoteException e) {
194 }
195 }
196 };
197
198 RemoteConnectionService(ComponentName componentName, ICallService callService)
199 throws RemoteException {
200 mComponentName = componentName;
201 mCallService = callService;
202
203 // TODO(santoscordon): Rename from setCallServiceAdapter to addCallServiceAdapter.
204 mCallService.setCallServiceAdapter(mAdapter);
205 mCallService.asBinder().linkToDeath(this, 0);
206 }
207
208 @Override
209 public String toString() {
210 return "[RemoteCS - " + mCallService.asBinder().toString() + "]";
211 }
212
213 /** ${inheritDoc} */
214 @Override
Sailesh Nepal091768c2014-06-30 15:15:23 -0700215 public final void binderDied() {
Santos Cordon52d8a152014-06-17 19:08:45 -0700216 if (mConnection != null) {
217 destroyConnection();
218 }
219
220 release();
221 }
222
223 /**
224 * Places an outgoing call.
225 */
Sailesh Nepal091768c2014-06-30 15:15:23 -0700226 public final void createOutgoingConnection(
Santos Cordon52d8a152014-06-17 19:08:45 -0700227 ConnectionRequest request,
Sailesh Nepal506e3862014-06-25 13:35:14 -0700228 ConnectionService.OutgoingCallResponse<RemoteConnection> response) {
Santos Cordon52d8a152014-06-17 19:08:45 -0700229
230 if (mConnectionId == null) {
231 String id = UUID.randomUUID().toString();
232 CallInfo callInfo = new CallInfo(id, CallState.NEW, request.getHandle());
233 try {
234 mCallService.call(callInfo);
235 mConnectionId = id;
Sailesh Nepal506e3862014-06-25 13:35:14 -0700236 mPendingOutgoingCallResponse = response;
Santos Cordon52d8a152014-06-17 19:08:45 -0700237 mPendingRequest = request;
238 } catch (RemoteException e) {
Sailesh Nepal506e3862014-06-25 13:35:14 -0700239 response.onFailure(request, DisconnectCause.ERROR_UNSPECIFIED, e.toString());
Santos Cordon52d8a152014-06-17 19:08:45 -0700240 }
241 } else {
Sailesh Nepal506e3862014-06-25 13:35:14 -0700242 response.onFailure(request, DisconnectCause.ERROR_UNSPECIFIED, null);
Santos Cordon52d8a152014-06-17 19:08:45 -0700243 }
244 }
245
246 // TODO(santoscordon): Handle incoming connections
Sailesh Nepal091768c2014-06-30 15:15:23 -0700247 // public final void handleIncomingConnection() {}
Santos Cordon52d8a152014-06-17 19:08:45 -0700248
Sailesh Nepal091768c2014-06-30 15:15:23 -0700249 public final List<Subscription> lookupSubscriptions(Uri handle) {
Santos Cordon52d8a152014-06-17 19:08:45 -0700250 // TODO(santoscordon): Update this so that is actually calls into the RemoteConnection
251 // each time.
252 List<Subscription> subscriptions = new LinkedList<>();
253 subscriptions.add(new Subscription(
254 mComponentName,
255 null /* id */,
256 null /* handle */,
257 0 /* labelResId */,
258 0 /* shortDescriptionResId */,
259 0 /* iconResId */,
260 true /* isEnabled */,
261 false /* isSystemDefault */));
262 return subscriptions;
263 }
264
265 /**
266 * Releases the resources associated with this Remote connection service. Should be called when
267 * the remote service is no longer being used.
268 */
269 void release() {
270 mCallService.asBinder().unlinkToDeath(this, 0);
271 }
272
273 private boolean isPendingConnection(String id) {
Sailesh Nepal506e3862014-06-25 13:35:14 -0700274 return TextUtils.equals(mConnectionId, id) && mPendingOutgoingCallResponse != null;
Santos Cordon52d8a152014-06-17 19:08:45 -0700275 }
276
277 private boolean isCurrentConnection(String id) {
278 return mConnection != null && TextUtils.equals(mConnectionId, id);
279 }
280
281 private void clearPendingInformation() {
282 mPendingRequest = null;
Sailesh Nepal506e3862014-06-25 13:35:14 -0700283 mPendingOutgoingCallResponse = null;
Santos Cordon52d8a152014-06-17 19:08:45 -0700284 }
285
286 private void destroyConnection() {
287 mConnection.setDestroyed();
288 mConnection = null;
289 mConnectionId = null;
290 }
291}