blob: 95b62ba65cf7e757e5d0114a632c5f977be8a3ff [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
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -070019import android.app.PendingIntent;
Santos Cordon52d8a152014-06-17 19:08:45 -070020import android.net.Uri;
Ihab Awad5d0410f2014-07-30 10:07:40 -070021import android.os.IBinder;
Santos Cordone8dc4be2014-07-21 01:28:28 -070022import android.os.IBinder.DeathRecipient;
Santos Cordon52d8a152014-06-17 19:08:45 -070023import android.os.RemoteException;
24import android.telephony.DisconnectCause;
Santos Cordon52d8a152014-06-17 19:08:45 -070025
Sailesh Nepal2a46b902014-07-04 17:21:07 -070026import com.android.internal.telecomm.IConnectionService;
27import com.android.internal.telecomm.IConnectionServiceAdapter;
Andrew Lee50aca232014-07-22 16:41:54 -070028import com.android.internal.telecomm.IVideoCallProvider;
Santos Cordon52d8a152014-06-17 19:08:45 -070029import com.android.internal.telecomm.RemoteServiceCallback;
30
Ihab Awad5d0410f2014-07-30 10:07:40 -070031import java.util.HashMap;
32import java.util.HashSet;
33import java.util.Map;
34import java.util.Set;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -070035import java.util.Collections;
36import java.util.List;
Santos Cordon52d8a152014-06-17 19:08:45 -070037import java.util.UUID;
38
39/**
40 * Remote connection service which other connection services can use to place calls on their behalf.
Sailesh Nepal091768c2014-06-30 15:15:23 -070041 *
42 * @hide
Santos Cordon52d8a152014-06-17 19:08:45 -070043 */
Ihab Awad5d0410f2014-07-30 10:07:40 -070044final class RemoteConnectionService {
Sailesh Nepal48031592014-07-18 14:21:23 -070045
Ihab Awad5d0410f2014-07-30 10:07:40 -070046 private static final RemoteConnection NULL_CONNECTION = new RemoteConnection(null, null);
Santos Cordon52d8a152014-06-17 19:08:45 -070047
Ihab Awad5d0410f2014-07-30 10:07:40 -070048 private final IConnectionServiceAdapter mServantDelegate = new IConnectionServiceAdapter() {
Sailesh Nepal48031592014-07-18 14:21:23 -070049 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -070050 public void handleCreateConnectionSuccessful(ConnectionRequest request,
51 ParcelableConnection parcel) {
52 RemoteConnection connection = findConnectionForAction(
53 request.getCallId(), "handleCreateConnectionSuccessful");
54 if (connection != NULL_CONNECTION && mPendingConnections.contains(connection)) {
55 mPendingConnections.remove(connection);
56 connection.setState(parcel.getState());
57 connection.setCallCapabilities(parcel.getCapabilities());
58 connection.setHandle(
59 parcel.getHandle(), parcel.getHandlePresentation());
60 connection.setCallerDisplayName(
61 parcel.getCallerDisplayName(),
62 parcel.getCallerDisplayNamePresentation());
63 // TODO: Do we need to support video providers for remote connections?
Sailesh Nepal48031592014-07-18 14:21:23 -070064 }
65 }
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -070066
Sailesh Nepal2a46b902014-07-04 17:21:07 -070067 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -070068 public void handleCreateConnectionFailed(ConnectionRequest request, int errorCode,
69 String errorMessage) {
70 // TODO: How do we propagate the failure codes?
71 findConnectionForAction(
72 request.getCallId(), "handleCreateConnectionFailed")
73 .setDestroyed();
Sailesh Nepal506e3862014-06-25 13:35:14 -070074 }
75
Sailesh Nepal2a46b902014-07-04 17:21:07 -070076 @Override
Sailesh Nepalc5b01572014-07-14 16:29:44 -070077 public void handleCreateConnectionCancelled(ConnectionRequest request) {
Ihab Awad5d0410f2014-07-30 10:07:40 -070078 findConnectionForAction(
79 request.getCallId(), "handleCreateConnectionCancelled")
80 .setDestroyed();
Santos Cordon52d8a152014-06-17 19:08:45 -070081 }
82
Sailesh Nepal2a46b902014-07-04 17:21:07 -070083 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -070084 public void setActive(String callId) {
85 findConnectionForAction(callId, "setActive")
86 .setState(Connection.State.ACTIVE);
Santos Cordon52d8a152014-06-17 19:08:45 -070087 }
88
Sailesh Nepal2a46b902014-07-04 17:21:07 -070089 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -070090 public void setRinging(String callId) {
91 findConnectionForAction(callId, "setRinging")
92 .setState(Connection.State.RINGING);
Andrew Lee5ffbe8b2014-06-20 16:29:33 -070093 }
94
Sailesh Nepal2a46b902014-07-04 17:21:07 -070095 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -070096 public void setDialing(String callId) {
97 findConnectionForAction(callId, "setDialing")
98 .setState(Connection.State.DIALING);
Santos Cordon52d8a152014-06-17 19:08:45 -070099 }
100
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700101 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -0700102 public void setDisconnected(String callId, int disconnectCause,
103 String disconnectMessage) {
104 findConnectionForAction(callId, "setDisconnected")
105 .setDisconnected(disconnectCause, disconnectMessage);
Santos Cordon52d8a152014-06-17 19:08:45 -0700106 }
107
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700108 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -0700109 public void setOnHold(String callId) {
110 findConnectionForAction(callId, "setOnHold")
111 .setState(Connection.State.HOLDING);
Santos Cordon52d8a152014-06-17 19:08:45 -0700112 }
113
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700114 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -0700115 public void setRequestingRingback(String callId, boolean ringing) {
116 findConnectionForAction(callId, "setRequestingRingback")
117 .setRequestingRingback(ringing);
Santos Cordon52d8a152014-06-17 19:08:45 -0700118 }
119
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700120 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -0700121 public void setCallCapabilities(String callId, int callCapabilities) {
122 findConnectionForAction("callId", "setCallCapabilities")
123 .setCallCapabilities(callCapabilities);
Santos Cordon52d8a152014-06-17 19:08:45 -0700124 }
125
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700126 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -0700127 public void setIsConferenced(String callId, String conferenceCallId) {
Santos Cordon52d8a152014-06-17 19:08:45 -0700128 // not supported for remote connections.
129 }
130
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700131 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -0700132 public void addConferenceCall(String callId) {
Santos Cordon52d8a152014-06-17 19:08:45 -0700133 // not supported for remote connections.
134 }
135
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700136 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -0700137 public void removeCall(String callId) {
138 findConnectionForAction(callId, "removeCall")
139 .setDestroyed();
Santos Cordon52d8a152014-06-17 19:08:45 -0700140 }
141
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700142 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -0700143 public void onPostDialWait(String callId, String remaining) {
144 findConnectionForAction(callId, "onPostDialWait")
145 .setPostDialWait(remaining);
Santos Cordon52d8a152014-06-17 19:08:45 -0700146 }
147
Santos Cordon52d8a152014-06-17 19:08:45 -0700148 @Override
149 public void queryRemoteConnectionServices(RemoteServiceCallback callback) {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700150 // Not supported from remote connection service.
Santos Cordon52d8a152014-06-17 19:08:45 -0700151 }
Tyler Gunn8d83fa92014-07-01 11:31:21 -0700152
Sailesh Nepal33aaae42014-07-07 22:49:44 -0700153 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -0700154 public void setVideoCallProvider(String callId,
155 IVideoCallProvider videoCallProvider) {
Sailesh Nepal48031592014-07-18 14:21:23 -0700156 // not supported for remote connections.
Tyler Gunnaa07df82014-07-17 07:50:22 -0700157 }
158
159 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -0700160 public void setVideoState(String callId, int videoState) {
161 findConnectionForAction(callId, "setVideoState")
162 .setVideoState(videoState);
Sailesh Nepal33aaae42014-07-07 22:49:44 -0700163 }
Sailesh Nepale7ef59a2014-07-08 21:48:22 -0700164
Sailesh Nepale7ef59a2014-07-08 21:48:22 -0700165 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -0700166 public void setAudioModeIsVoip(String callId, boolean isVoip) {
167 findConnectionForAction(callId, "setAudioModeIsVoip")
168 .setAudioModeIsVoip(isVoip);
Sailesh Nepale7ef59a2014-07-08 21:48:22 -0700169 }
Sailesh Nepal61203862014-07-11 14:50:13 -0700170
171 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -0700172 public void setStatusHints(String callId, StatusHints statusHints) {
173 findConnectionForAction(callId, "setStatusHints")
174 .setStatusHints(statusHints);
Sailesh Nepal61203862014-07-11 14:50:13 -0700175 }
176
177 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -0700178 public void setHandle(String callId, Uri handle, int presentation) {
179 findConnectionForAction(callId, "setHandle")
180 .setHandle(handle, presentation);
Sailesh Nepal61203862014-07-11 14:50:13 -0700181 }
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -0700182
183 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -0700184 public void setCallerDisplayName(String callId, String callerDisplayName,
185 int presentation) {
186 findConnectionForAction(callId, "setCallerDisplayName")
187 .setCallerDisplayName(callerDisplayName, presentation);
188 }
189
190 @Override
191 public void startActivityFromInCall(String callId, PendingIntent intent) {
192 findConnectionForAction(callId, "startActivityFromInCall")
193 .startActivityFromInCall(intent);
194 }
195
196 @Override
197 public IBinder asBinder() {
198 throw new UnsupportedOperationException();
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -0700199 }
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700200
201 @Override
202 public final void setConferenceableConnections(
203 String callId, List<String> conferenceableConnectionIds) {
204
205 // TODO: When we support more than 1 remote connection, this should
206 // loop through the incoming list of connection IDs and acquire the list
207 // of remote connections which correspond to the IDs. That list should
208 // be set onto the remote connections.
209 findConnectionForAction(callId, "setConferenceableConnections")
210 .setConferenceableConnections(Collections.<RemoteConnection>emptyList());
211 }
Santos Cordon52d8a152014-06-17 19:08:45 -0700212 };
213
Ihab Awad5d0410f2014-07-30 10:07:40 -0700214 private final ConnectionServiceAdapterServant mServant =
215 new ConnectionServiceAdapterServant(mServantDelegate);
Santos Cordon52d8a152014-06-17 19:08:45 -0700216
Ihab Awad5d0410f2014-07-30 10:07:40 -0700217 private final DeathRecipient mDeathRecipient = new DeathRecipient() {
218 @Override
219 public void binderDied() {
220 for (RemoteConnection c : mConnectionById.values()) {
221 c.setDestroyed();
222 }
223 mConnectionById.clear();
224 mPendingConnections.clear();
225 mConnectionService.asBinder().unlinkToDeath(mDeathRecipient, 0);
226 }
227 };
228
229 private final IConnectionService mConnectionService;
230 private final Map<String, RemoteConnection> mConnectionById = new HashMap<>();
231 private final Set<RemoteConnection> mPendingConnections = new HashSet<>();
232
233 RemoteConnectionService(IConnectionService connectionService) throws RemoteException {
234 mConnectionService = connectionService;
Ihab Awad5d0410f2014-07-30 10:07:40 -0700235 mConnectionService.asBinder().linkToDeath(mDeathRecipient, 0);
Santos Cordon52d8a152014-06-17 19:08:45 -0700236 }
237
238 @Override
239 public String toString() {
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700240 return "[RemoteCS - " + mConnectionService.asBinder().toString() + "]";
Santos Cordon52d8a152014-06-17 19:08:45 -0700241 }
242
Ihab Awadf8b69882014-07-25 15:14:01 -0700243 final RemoteConnection createRemoteConnection(
244 PhoneAccountHandle connectionManagerPhoneAccount,
245 ConnectionRequest request,
246 boolean isIncoming) {
Ihab Awad8aecfed2014-08-08 17:06:11 -0700247 final ConnectionRequest newRequest = new ConnectionRequest(
Ihab Awad5d0410f2014-07-30 10:07:40 -0700248 request.getAccountHandle(),
249 UUID.randomUUID().toString(),
250 request.getHandle(),
251 request.getHandlePresentation(),
252 request.getExtras(),
253 request.getVideoState());
254 try {
Ihab Awad8aecfed2014-08-08 17:06:11 -0700255 if (mConnectionById.isEmpty()) {
256 mConnectionService.addConnectionServiceAdapter(mServant.getStub());
257 }
258 RemoteConnection connection =
259 new RemoteConnection(mConnectionService, newRequest);
260 mPendingConnections.add(connection);
261 mConnectionById.put(newRequest.getCallId(), connection);
Ihab Awad5d0410f2014-07-30 10:07:40 -0700262 mConnectionService.createConnection(
263 connectionManagerPhoneAccount,
264 newRequest,
265 isIncoming);
Ihab Awad8aecfed2014-08-08 17:06:11 -0700266 connection.addListener(new RemoteConnection.Listener() {
267 @Override
268 public void onDestroyed(RemoteConnection connection) {
269 mConnectionById.remove(newRequest.getCallId());
270 if (mConnectionById.isEmpty()) {
271 try {
272 mConnectionService.removeConnectionServiceAdapter(mServant.getStub());
273 } catch (RemoteException e) {
274 }
275 }
276 }
277 });
Ihab Awad5d0410f2014-07-30 10:07:40 -0700278 return connection;
279 } catch (RemoteException e) {
280 return RemoteConnection.failure(DisconnectCause.ERROR_UNSPECIFIED, e.toString());
Santos Cordon52d8a152014-06-17 19:08:45 -0700281 }
282 }
283
Ihab Awad5d0410f2014-07-30 10:07:40 -0700284 private RemoteConnection findConnectionForAction(String callId, String action) {
285 if (mConnectionById.containsKey(callId)) {
286 return mConnectionById.get(callId);
287 }
288 Log.w(this, "%s - Cannot find Connection %s", action, callId);
289 return NULL_CONNECTION;
Santos Cordon52d8a152014-06-17 19:08:45 -0700290 }
291}