blob: efe35d21c00316af4a4ca5e9a9fbce3c591b4418 [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
Ihab Awadb19a0bc2014-08-07 19:46:01 -070014 * limitations under the License.
Santos Cordon52d8a152014-06-17 19:08:45 -070015 */
16
Tyler Gunnef9f6f92014-09-12 22:16:17 -070017package android.telecom;
Santos Cordon52d8a152014-06-17 19:08:45 -070018
Santos Cordon52d8a152014-06-17 19:08:45 -070019import android.net.Uri;
Santos Cordon6b7f9552015-05-27 17:21:45 -070020import android.os.Bundle;
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;
Brad Ebinger4d75bee2016-10-28 12:29:55 -070024import android.telecom.Logging.Session;
Santos Cordon52d8a152014-06-17 19:08:45 -070025
Tyler Gunnef9f6f92014-09-12 22:16:17 -070026import com.android.internal.telecom.IConnectionService;
27import com.android.internal.telecom.IConnectionServiceAdapter;
28import com.android.internal.telecom.IVideoProvider;
29import com.android.internal.telecom.RemoteServiceCallback;
Santos Cordon52d8a152014-06-17 19:08:45 -070030
Ihab Awadb8e85c72014-08-23 20:34:57 -070031import java.util.ArrayList;
Ihab Awad5d0410f2014-07-30 10:07:40 -070032import java.util.HashMap;
33import java.util.HashSet;
Grace Jia9a09c672020-08-04 12:52:09 -070034import java.util.List;
Ihab Awad5d0410f2014-07-30 10:07:40 -070035import java.util.Map;
36import java.util.Set;
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
Tyler Gunn4a57b9b2014-10-30 14:27:48 -070046 // Note: Casting null to avoid ambiguous constructor reference.
Ihab Awadb8e85c72014-08-23 20:34:57 -070047 private static final RemoteConnection NULL_CONNECTION =
Tyler Gunn4a57b9b2014-10-30 14:27:48 -070048 new RemoteConnection("NULL", null, (ConnectionRequest) null);
Ihab Awadb8e85c72014-08-23 20:34:57 -070049
50 private static final RemoteConference NULL_CONFERENCE =
51 new RemoteConference("NULL", null);
Santos Cordon52d8a152014-06-17 19:08:45 -070052
Ihab Awad5d0410f2014-07-30 10:07:40 -070053 private final IConnectionServiceAdapter mServantDelegate = new IConnectionServiceAdapter() {
Sailesh Nepal48031592014-07-18 14:21:23 -070054 @Override
Ihab Awad6107bab2014-08-18 09:23:25 -070055 public void handleCreateConnectionComplete(
Ihab Awadb19a0bc2014-08-07 19:46:01 -070056 String id,
57 ConnectionRequest request,
Brad Ebinger4d75bee2016-10-28 12:29:55 -070058 ParcelableConnection parcel,
59 Session.Info info) {
Ihab Awadb19a0bc2014-08-07 19:46:01 -070060 RemoteConnection connection =
61 findConnectionForAction(id, "handleCreateConnectionSuccessful");
Ihab Awad5d0410f2014-07-30 10:07:40 -070062 if (connection != NULL_CONNECTION && mPendingConnections.contains(connection)) {
63 mPendingConnections.remove(connection);
Ihab Awad6107bab2014-08-18 09:23:25 -070064 // Unconditionally initialize the connection ...
Ihab Awad5c9c86e2014-11-12 13:41:16 -080065 connection.setConnectionCapabilities(parcel.getConnectionCapabilities());
Tyler Gunn720c6642016-03-22 09:02:47 -070066 connection.setConnectionProperties(parcel.getConnectionProperties());
Sailesh Nepal2d3ced72015-01-31 20:17:35 -080067 if (parcel.getHandle() != null
68 || parcel.getState() != Connection.STATE_DISCONNECTED) {
69 connection.setAddress(parcel.getHandle(), parcel.getHandlePresentation());
70 }
71 if (parcel.getCallerDisplayName() != null
72 || parcel.getState() != Connection.STATE_DISCONNECTED) {
73 connection.setCallerDisplayName(
74 parcel.getCallerDisplayName(),
75 parcel.getCallerDisplayNamePresentation());
76 }
Sailesh Nepal70638f12014-09-09 21:49:14 -070077 // Set state after handle so that the client can identify the connection.
Sailesh Nepalc2a978d2014-09-20 18:23:05 -070078 if (parcel.getState() == Connection.STATE_DISCONNECTED) {
79 connection.setDisconnected(parcel.getDisconnectCause());
80 } else {
81 connection.setState(parcel.getState());
82 }
Ihab Awadb8e85c72014-08-23 20:34:57 -070083 List<RemoteConnection> conferenceable = new ArrayList<>();
84 for (String confId : parcel.getConferenceableConnectionIds()) {
85 if (mConnectionById.containsKey(confId)) {
86 conferenceable.add(mConnectionById.get(confId));
87 }
88 }
89 connection.setConferenceableConnections(conferenceable);
Ihab Awada64627c2014-08-20 09:36:40 -070090 connection.setVideoState(parcel.getVideoState());
Ihab Awad6107bab2014-08-18 09:23:25 -070091 if (connection.getState() == Connection.STATE_DISCONNECTED) {
92 // ... then, if it was created in a disconnected state, that indicates
93 // failure on the providing end, so immediately mark it destroyed
94 connection.setDestroyed();
95 }
Tyler Gunn31f0e0b2018-02-13 08:39:45 -080096 connection.setStatusHints(parcel.getStatusHints());
97 connection.setIsVoipAudioMode(parcel.getIsVoipAudioMode());
98 connection.setRingbackRequested(parcel.isRingbackRequested());
99 connection.putExtras(parcel.getExtras());
Sailesh Nepal48031592014-07-18 14:21:23 -0700100 }
101 }
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -0700102
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700103 @Override
Ravi Paluri80aa2142019-12-02 11:57:37 +0530104 public void handleCreateConferenceComplete(
105 String id,
106 ConnectionRequest request,
107 ParcelableConference parcel,
108 Session.Info info) {
109 }
110
111 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700112 public void setActive(String callId, Session.Info sessionInfo) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700113 if (mConnectionById.containsKey(callId)) {
114 findConnectionForAction(callId, "setActive")
115 .setState(Connection.STATE_ACTIVE);
116 } else {
117 findConferenceForAction(callId, "setActive")
118 .setState(Connection.STATE_ACTIVE);
119 }
Santos Cordon52d8a152014-06-17 19:08:45 -0700120 }
121
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700122 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700123 public void setRinging(String callId, Session.Info sessionInfo) {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700124 findConnectionForAction(callId, "setRinging")
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700125 .setState(Connection.STATE_RINGING);
Andrew Lee5ffbe8b82014-06-20 16:29:33 -0700126 }
127
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700128 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700129 public void setDialing(String callId, Session.Info sessionInfo) {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700130 findConnectionForAction(callId, "setDialing")
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700131 .setState(Connection.STATE_DIALING);
Santos Cordon52d8a152014-06-17 19:08:45 -0700132 }
133
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700134 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700135 public void setPulling(String callId, Session.Info sessionInfo) {
Tyler Gunnc96b5e02016-07-07 22:53:57 -0700136 findConnectionForAction(callId, "setPulling")
137 .setState(Connection.STATE_PULLING_CALL);
138 }
139
140 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700141 public void setDisconnected(String callId, DisconnectCause disconnectCause,
142 Session.Info sessionInfo) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700143 if (mConnectionById.containsKey(callId)) {
144 findConnectionForAction(callId, "setDisconnected")
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700145 .setDisconnected(disconnectCause);
Ihab Awadb8e85c72014-08-23 20:34:57 -0700146 } else {
147 findConferenceForAction(callId, "setDisconnected")
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700148 .setDisconnected(disconnectCause);
Ihab Awadb8e85c72014-08-23 20:34:57 -0700149 }
Santos Cordon52d8a152014-06-17 19:08:45 -0700150 }
151
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700152 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700153 public void setOnHold(String callId, Session.Info sessionInfo) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700154 if (mConnectionById.containsKey(callId)) {
155 findConnectionForAction(callId, "setOnHold")
156 .setState(Connection.STATE_HOLDING);
157 } else {
158 findConferenceForAction(callId, "setOnHold")
159 .setState(Connection.STATE_HOLDING);
160 }
Santos Cordon52d8a152014-06-17 19:08:45 -0700161 }
162
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700163 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700164 public void setRingbackRequested(String callId, boolean ringing, Session.Info sessionInfo) {
Andrew Lee100e2932014-09-08 15:34:24 -0700165 findConnectionForAction(callId, "setRingbackRequested")
166 .setRingbackRequested(ringing);
Santos Cordon52d8a152014-06-17 19:08:45 -0700167 }
168
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700169 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700170 public void setConnectionCapabilities(String callId, int connectionCapabilities,
171 Session.Info sessionInfo) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700172 if (mConnectionById.containsKey(callId)) {
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800173 findConnectionForAction(callId, "setConnectionCapabilities")
174 .setConnectionCapabilities(connectionCapabilities);
Ihab Awadb8e85c72014-08-23 20:34:57 -0700175 } else {
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800176 findConferenceForAction(callId, "setConnectionCapabilities")
177 .setConnectionCapabilities(connectionCapabilities);
Ihab Awadb8e85c72014-08-23 20:34:57 -0700178 }
Santos Cordon52d8a152014-06-17 19:08:45 -0700179 }
180
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700181 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700182 public void setConnectionProperties(String callId, int connectionProperties,
183 Session.Info sessionInfo) {
Tyler Gunn720c6642016-03-22 09:02:47 -0700184 if (mConnectionById.containsKey(callId)) {
185 findConnectionForAction(callId, "setConnectionProperties")
186 .setConnectionProperties(connectionProperties);
187 } else {
188 findConferenceForAction(callId, "setConnectionProperties")
189 .setConnectionProperties(connectionProperties);
190 }
191 }
192
193 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700194 public void setIsConferenced(String callId, String conferenceCallId,
195 Session.Info sessionInfo) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700196 // Note: callId should not be null; conferenceCallId may be null
197 RemoteConnection connection =
198 findConnectionForAction(callId, "setIsConferenced");
199 if (connection != NULL_CONNECTION) {
200 if (conferenceCallId == null) {
201 // 'connection' is being split from its conference
202 if (connection.getConference() != null) {
203 connection.getConference().removeConnection(connection);
204 }
205 } else {
206 RemoteConference conference =
207 findConferenceForAction(conferenceCallId, "setIsConferenced");
208 if (conference != NULL_CONFERENCE) {
209 conference.addConnection(connection);
210 }
211 }
212 }
Santos Cordon52d8a152014-06-17 19:08:45 -0700213 }
214
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700215 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700216 public void setConferenceMergeFailed(String callId, Session.Info sessionInfo) {
Anthony Lee17455a32015-04-24 15:25:29 -0700217 // Nothing to do here.
218 // The event has already been handled and there is no state to update
219 // in the underlying connection or conference objects
220 }
221
222 @Override
Srikanth Chintalafcb15012017-05-04 20:58:34 +0530223 public void onPhoneAccountChanged(String callId, PhoneAccountHandle pHandle,
224 Session.Info sessionInfo) {
225 }
226
227 @Override
Pengquan Meng63d25a52017-11-21 18:01:13 -0800228 public void onConnectionServiceFocusReleased(Session.Info sessionInfo) {}
229
230 @Override
Ihab Awadb8e85c72014-08-23 20:34:57 -0700231 public void addConferenceCall(
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700232 final String callId, ParcelableConference parcel, Session.Info sessionInfo) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700233 RemoteConference conference = new RemoteConference(callId,
234 mOutgoingConnectionServiceRpc);
235
236 for (String id : parcel.getConnectionIds()) {
237 RemoteConnection c = mConnectionById.get(id);
238 if (c != null) {
239 conference.addConnection(c);
240 }
241 }
Tyler Gunn2d4fcc12021-06-24 11:25:07 -0700242 // We used to skip adding empty conferences; however in the world of IMS conference
243 // calls we need to add them to the remote connection service because they will always
244 // start with no participants.
Ihab Awadb8e85c72014-08-23 20:34:57 -0700245
246 conference.setState(parcel.getState());
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800247 conference.setConnectionCapabilities(parcel.getConnectionCapabilities());
Tyler Gunn04ce7572016-08-15 10:56:12 -0700248 conference.setConnectionProperties(parcel.getConnectionProperties());
Tyler Gunncd6ccfd2016-10-17 15:48:19 -0700249 conference.putExtras(parcel.getExtras());
Ihab Awadb8e85c72014-08-23 20:34:57 -0700250 mConferenceById.put(callId, conference);
Tyler Gunncd6ccfd2016-10-17 15:48:19 -0700251
252 // Stash the original connection ID as it exists in the source ConnectionService.
253 // Telecom will use this to avoid adding duplicates later.
254 // See comments on Connection.EXTRA_ORIGINAL_CONNECTION_ID for more information.
255 Bundle newExtras = new Bundle();
256 newExtras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
Tyler Gunnc59fd0c2020-04-17 14:03:35 -0700257 // Track the fact this request was relayed through the remote connection service.
258 newExtras.putParcelable(Connection.EXTRA_REMOTE_PHONE_ACCOUNT_HANDLE,
259 parcel.getPhoneAccount());
Tyler Gunncd6ccfd2016-10-17 15:48:19 -0700260 conference.putExtras(newExtras);
261
Andrew Lee100e2932014-09-08 15:34:24 -0700262 conference.registerCallback(new RemoteConference.Callback() {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700263 @Override
264 public void onDestroyed(RemoteConference c) {
265 mConferenceById.remove(callId);
266 maybeDisconnectAdapter();
267 }
268 });
269
270 mOurConnectionServiceImpl.addRemoteConference(conference);
Santos Cordon52d8a152014-06-17 19:08:45 -0700271 }
272
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700273 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700274 public void removeCall(String callId, Session.Info sessionInfo) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700275 if (mConnectionById.containsKey(callId)) {
276 findConnectionForAction(callId, "removeCall")
277 .setDestroyed();
278 } else {
279 findConferenceForAction(callId, "removeCall")
280 .setDestroyed();
281 }
Santos Cordon52d8a152014-06-17 19:08:45 -0700282 }
283
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700284 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700285 public void onPostDialWait(String callId, String remaining, Session.Info sessionInfo) {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700286 findConnectionForAction(callId, "onPostDialWait")
287 .setPostDialWait(remaining);
Santos Cordon52d8a152014-06-17 19:08:45 -0700288 }
289
Santos Cordon52d8a152014-06-17 19:08:45 -0700290 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700291 public void onPostDialChar(String callId, char nextChar, Session.Info sessionInfo) {
Nancy Chen27d1c2d2014-12-15 16:12:50 -0800292 findConnectionForAction(callId, "onPostDialChar")
293 .onPostDialChar(nextChar);
294 }
295
296 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700297 public void queryRemoteConnectionServices(RemoteServiceCallback callback,
Tyler Gunn4c69fb32019-05-17 10:49:16 -0700298 String callingPackage, Session.Info sessionInfo) {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700299 // Not supported from remote connection service.
Santos Cordon52d8a152014-06-17 19:08:45 -0700300 }
Tyler Gunn8d83fa92014-07-01 11:31:21 -0700301
Sailesh Nepal33aaae42014-07-07 22:49:44 -0700302 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700303 public void setVideoProvider(String callId, IVideoProvider videoProvider,
304 Session.Info sessionInfo) {
Tyler Gunnbf9c6fd2016-11-09 10:19:23 -0800305
306 String callingPackage = mOurConnectionServiceImpl.getApplicationContext()
307 .getOpPackageName();
Tyler Gunn159f35c2017-03-02 09:28:37 -0800308 int targetSdkVersion = mOurConnectionServiceImpl.getApplicationInfo().targetSdkVersion;
Sailesh Nepal11aeae52015-01-28 16:54:09 -0800309 RemoteConnection.VideoProvider remoteVideoProvider = null;
310 if (videoProvider != null) {
Tyler Gunnbf9c6fd2016-11-09 10:19:23 -0800311 remoteVideoProvider = new RemoteConnection.VideoProvider(videoProvider,
Tyler Gunn159f35c2017-03-02 09:28:37 -0800312 callingPackage, targetSdkVersion);
Sailesh Nepal11aeae52015-01-28 16:54:09 -0800313 }
Ihab Awada64627c2014-08-20 09:36:40 -0700314 findConnectionForAction(callId, "setVideoProvider")
Sailesh Nepal11aeae52015-01-28 16:54:09 -0800315 .setVideoProvider(remoteVideoProvider);
Tyler Gunnaa07df82014-07-17 07:50:22 -0700316 }
317
318 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700319 public void setVideoState(String callId, int videoState, Session.Info sessionInfo) {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700320 findConnectionForAction(callId, "setVideoState")
321 .setVideoState(videoState);
Sailesh Nepal33aaae42014-07-07 22:49:44 -0700322 }
Sailesh Nepale7ef59a2014-07-08 21:48:22 -0700323
Sailesh Nepale7ef59a2014-07-08 21:48:22 -0700324 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700325 public void setIsVoipAudioMode(String callId, boolean isVoip, Session.Info sessionInfo) {
Andrew Lee100e2932014-09-08 15:34:24 -0700326 findConnectionForAction(callId, "setIsVoipAudioMode")
327 .setIsVoipAudioMode(isVoip);
Sailesh Nepale7ef59a2014-07-08 21:48:22 -0700328 }
Sailesh Nepal61203862014-07-11 14:50:13 -0700329
330 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700331 public void setStatusHints(String callId, StatusHints statusHints,
332 Session.Info sessionInfo) {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700333 findConnectionForAction(callId, "setStatusHints")
334 .setStatusHints(statusHints);
Sailesh Nepal61203862014-07-11 14:50:13 -0700335 }
336
337 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700338 public void setAddress(String callId, Uri address, int presentation,
339 Session.Info sessionInfo) {
Andrew Lee100e2932014-09-08 15:34:24 -0700340 findConnectionForAction(callId, "setAddress")
341 .setAddress(address, presentation);
Sailesh Nepal61203862014-07-11 14:50:13 -0700342 }
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -0700343
344 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -0700345 public void setCallerDisplayName(String callId, String callerDisplayName,
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700346 int presentation, Session.Info sessionInfo) {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700347 findConnectionForAction(callId, "setCallerDisplayName")
348 .setCallerDisplayName(callerDisplayName, presentation);
349 }
350
351 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -0700352 public IBinder asBinder() {
353 throw new UnsupportedOperationException();
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -0700354 }
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700355
356 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700357 public final void setConferenceableConnections(String callId,
358 List<String> conferenceableConnectionIds, Session.Info sessionInfo) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700359 List<RemoteConnection> conferenceable = new ArrayList<>();
360 for (String id : conferenceableConnectionIds) {
361 if (mConnectionById.containsKey(id)) {
362 conferenceable.add(mConnectionById.get(id));
363 }
364 }
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700365
Ihab Awad50e35062014-09-30 09:17:03 -0700366 if (hasConnection(callId)) {
367 findConnectionForAction(callId, "setConferenceableConnections")
368 .setConferenceableConnections(conferenceable);
369 } else {
370 findConferenceForAction(callId, "setConferenceableConnections")
371 .setConferenceableConnections(conferenceable);
372 }
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700373 }
Tyler Gunn4a57b9b2014-10-30 14:27:48 -0700374
375 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700376 public void addExistingConnection(String callId, ParcelableConnection connection,
377 Session.Info sessionInfo) {
Tyler Gunn2d4fcc12021-06-24 11:25:07 -0700378 Log.i(RemoteConnectionService.this, "addExistingConnection: callId=%s, conn=%s", callId,
379 connection);
Tyler Gunnbf9c6fd2016-11-09 10:19:23 -0800380 String callingPackage = mOurConnectionServiceImpl.getApplicationContext().
381 getOpPackageName();
Tyler Gunn159f35c2017-03-02 09:28:37 -0800382 int callingTargetSdkVersion = mOurConnectionServiceImpl.getApplicationInfo()
383 .targetSdkVersion;
Tyler Gunncd6ccfd2016-10-17 15:48:19 -0700384 RemoteConnection remoteConnection = new RemoteConnection(callId,
Tyler Gunn159f35c2017-03-02 09:28:37 -0800385 mOutgoingConnectionServiceRpc, connection, callingPackage,
386 callingTargetSdkVersion);
Tyler Gunnc59fd0c2020-04-17 14:03:35 -0700387 // Track that it is via a remote connection.
388 Bundle newExtras = new Bundle();
389 newExtras.putParcelable(Connection.EXTRA_REMOTE_PHONE_ACCOUNT_HANDLE,
390 connection.getPhoneAccount());
Tyler Gunn2d4fcc12021-06-24 11:25:07 -0700391 if (connection.getParentCallId() != null) {
392 RemoteConference parentConf = mConferenceById.get(connection.getParentCallId());
393 // If there is a parent being set, we need to stash the conference ID here.
394 // Telephony can add an existing connection while specifying a parent conference.
395 // There is no equivalent version of that operation as part of the remote connection
396 // API, so we will stash the pre-defined parent's ID in the extras. When the
397 // connectionmanager copies over the extras from the remote connection to the
398 // actual one, it'll get passed to Telecom so that it can make the association.
399 if (parentConf != null) {
400 newExtras.putString(Connection.EXTRA_ADD_TO_CONFERENCE_ID, parentConf.getId());
401 Log.i(this, "addExistingConnection: stash parent of %s as %s",
402 connection.getParentCallId(), parentConf.getId());
403 }
404 }
Tyler Gunnc59fd0c2020-04-17 14:03:35 -0700405 remoteConnection.putExtras(newExtras);
Tyler Gunncd6ccfd2016-10-17 15:48:19 -0700406 mConnectionById.put(callId, remoteConnection);
407 remoteConnection.registerCallback(new RemoteConnection.Callback() {
408 @Override
409 public void onDestroyed(RemoteConnection connection) {
410 mConnectionById.remove(callId);
411 maybeDisconnectAdapter();
412 }
413 });
414 mOurConnectionServiceImpl.addRemoteExistingConnection(remoteConnection);
Tyler Gunn4a57b9b2014-10-30 14:27:48 -0700415 }
Santos Cordon6b7f9552015-05-27 17:21:45 -0700416
417 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700418 public void putExtras(String callId, Bundle extras, Session.Info sessionInfo) {
Tyler Gunndee56a82016-03-23 16:06:34 -0700419 if (hasConnection(callId)) {
420 findConnectionForAction(callId, "putExtras").putExtras(extras);
Santos Cordon6b7f9552015-05-27 17:21:45 -0700421 } else {
Tyler Gunndee56a82016-03-23 16:06:34 -0700422 findConferenceForAction(callId, "putExtras").putExtras(extras);
423 }
424 }
425
426 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700427 public void removeExtras(String callId, List<String> keys, Session.Info sessionInfo) {
Tyler Gunndee56a82016-03-23 16:06:34 -0700428 if (hasConnection(callId)) {
429 findConnectionForAction(callId, "removeExtra").removeExtras(keys);
430 } else {
431 findConferenceForAction(callId, "removeExtra").removeExtras(keys);
Santos Cordon6b7f9552015-05-27 17:21:45 -0700432 }
433 }
Tyler Gunnbd1eb1f2016-02-16 14:36:20 -0800434
435 @Override
Hall Liua98f58b52017-11-07 17:59:28 -0800436 public void setAudioRoute(String callId, int audioRoute, String bluetoothAddress,
437 Session.Info sessionInfo) {
Tyler Gunnf5035432017-01-09 09:43:12 -0800438 if (hasConnection(callId)) {
439 // TODO(3pcalls): handle this for remote connections.
440 // Likely we don't want to do anything since it doesn't make sense for self-managed
441 // connections to go through a connection mgr.
442 }
443 }
444
445 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700446 public void onConnectionEvent(String callId, String event, Bundle extras,
447 Session.Info sessionInfo) {
Tyler Gunnbd1eb1f2016-02-16 14:36:20 -0800448 if (mConnectionById.containsKey(callId)) {
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700449 findConnectionForAction(callId, "onConnectionEvent").onConnectionEvent(event,
450 extras);
Tyler Gunnbd1eb1f2016-02-16 14:36:20 -0800451 }
452 }
Hall Liu57006aa2017-02-06 10:49:48 -0800453
454 @Override
455 public void onRttInitiationSuccess(String callId, Session.Info sessionInfo)
456 throws RemoteException {
457 if (hasConnection(callId)) {
458 findConnectionForAction(callId, "onRttInitiationSuccess")
459 .onRttInitiationSuccess();
460 } else {
461 Log.w(this, "onRttInitiationSuccess called on a remote conference");
462 }
463 }
464
465 @Override
466 public void onRttInitiationFailure(String callId, int reason, Session.Info sessionInfo)
467 throws RemoteException {
468 if (hasConnection(callId)) {
469 findConnectionForAction(callId, "onRttInitiationFailure")
470 .onRttInitiationFailure(reason);
471 } else {
472 Log.w(this, "onRttInitiationFailure called on a remote conference");
473 }
474 }
475
476 @Override
477 public void onRttSessionRemotelyTerminated(String callId, Session.Info sessionInfo)
478 throws RemoteException {
479 if (hasConnection(callId)) {
480 findConnectionForAction(callId, "onRttSessionRemotelyTerminated")
481 .onRttSessionRemotelyTerminated();
482 } else {
483 Log.w(this, "onRttSessionRemotelyTerminated called on a remote conference");
484 }
485 }
486
487 @Override
488 public void onRemoteRttRequest(String callId, Session.Info sessionInfo)
489 throws RemoteException {
490 if (hasConnection(callId)) {
491 findConnectionForAction(callId, "onRemoteRttRequest")
492 .onRemoteRttRequest();
493 } else {
494 Log.w(this, "onRemoteRttRequest called on a remote conference");
495 }
496 }
Mengjun Leng25707742017-07-04 11:10:37 +0800497
498 @Override
499 public void resetConnectionTime(String callId, Session.Info sessionInfo) {
500 // Do nothing
501 }
Tyler Gunn68a73a42018-10-03 15:38:57 -0700502
503 @Override
504 public void setConferenceState(String callId, boolean isConference,
505 Session.Info sessionInfo) {
506 // Do nothing
507 }
Brad Ebingere0c12f42020-04-08 16:25:12 -0700508
509 @Override
510 public void setCallDirection(String callId, int direction, Session.Info sessionInfo) {
511 // Do nothing
512 }
Santos Cordon52d8a152014-06-17 19:08:45 -0700513 };
514
Ihab Awad5d0410f2014-07-30 10:07:40 -0700515 private final ConnectionServiceAdapterServant mServant =
516 new ConnectionServiceAdapterServant(mServantDelegate);
Santos Cordon52d8a152014-06-17 19:08:45 -0700517
Ihab Awad5d0410f2014-07-30 10:07:40 -0700518 private final DeathRecipient mDeathRecipient = new DeathRecipient() {
519 @Override
520 public void binderDied() {
521 for (RemoteConnection c : mConnectionById.values()) {
522 c.setDestroyed();
523 }
Ihab Awadb8e85c72014-08-23 20:34:57 -0700524 for (RemoteConference c : mConferenceById.values()) {
525 c.setDestroyed();
526 }
Ihab Awad5d0410f2014-07-30 10:07:40 -0700527 mConnectionById.clear();
Ihab Awadb8e85c72014-08-23 20:34:57 -0700528 mConferenceById.clear();
Ihab Awad5d0410f2014-07-30 10:07:40 -0700529 mPendingConnections.clear();
Ihab Awadb8e85c72014-08-23 20:34:57 -0700530 mOutgoingConnectionServiceRpc.asBinder().unlinkToDeath(mDeathRecipient, 0);
Ihab Awad5d0410f2014-07-30 10:07:40 -0700531 }
532 };
533
Ihab Awadb8e85c72014-08-23 20:34:57 -0700534 private final IConnectionService mOutgoingConnectionServiceRpc;
535 private final ConnectionService mOurConnectionServiceImpl;
Ihab Awad5d0410f2014-07-30 10:07:40 -0700536 private final Map<String, RemoteConnection> mConnectionById = new HashMap<>();
Ihab Awadb8e85c72014-08-23 20:34:57 -0700537 private final Map<String, RemoteConference> mConferenceById = new HashMap<>();
Ihab Awad5d0410f2014-07-30 10:07:40 -0700538 private final Set<RemoteConnection> mPendingConnections = new HashSet<>();
539
Ihab Awadb8e85c72014-08-23 20:34:57 -0700540 RemoteConnectionService(
541 IConnectionService outgoingConnectionServiceRpc,
542 ConnectionService ourConnectionServiceImpl) throws RemoteException {
543 mOutgoingConnectionServiceRpc = outgoingConnectionServiceRpc;
544 mOutgoingConnectionServiceRpc.asBinder().linkToDeath(mDeathRecipient, 0);
545 mOurConnectionServiceImpl = ourConnectionServiceImpl;
Santos Cordon52d8a152014-06-17 19:08:45 -0700546 }
547
548 @Override
549 public String toString() {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700550 return "[RemoteCS - " + mOutgoingConnectionServiceRpc.asBinder().toString() + "]";
Santos Cordon52d8a152014-06-17 19:08:45 -0700551 }
552
Ihab Awadf8b69882014-07-25 15:14:01 -0700553 final RemoteConnection createRemoteConnection(
554 PhoneAccountHandle connectionManagerPhoneAccount,
555 ConnectionRequest request,
556 boolean isIncoming) {
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700557 final String id = UUID.randomUUID().toString();
Tyler Gunnc59fd0c2020-04-17 14:03:35 -0700558 Bundle extras = new Bundle();
559 if (request.getExtras() != null) {
560 extras.putAll(request.getExtras());
561 }
562 // We will set the package name for the originator of the remote request; this lets the
563 // receiving ConnectionService know that the request originated from a remote connection
564 // service so that it can provide tracking information for Telecom.
565 extras.putString(Connection.EXTRA_REMOTE_CONNECTION_ORIGINATING_PACKAGE_NAME,
566 mOurConnectionServiceImpl.getApplicationContext().getOpPackageName());
567
Hall Liu95d55872017-01-25 17:12:49 -0800568 final ConnectionRequest newRequest = new ConnectionRequest.Builder()
569 .setAccountHandle(request.getAccountHandle())
570 .setAddress(request.getAddress())
Tyler Gunnc59fd0c2020-04-17 14:03:35 -0700571 .setExtras(extras)
Hall Liu95d55872017-01-25 17:12:49 -0800572 .setVideoState(request.getVideoState())
573 .setRttPipeFromInCall(request.getRttPipeFromInCall())
574 .setRttPipeToInCall(request.getRttPipeToInCall())
575 .build();
Ihab Awad5d0410f2014-07-30 10:07:40 -0700576 try {
Ihab Awad8aecfed2014-08-08 17:06:11 -0700577 if (mConnectionById.isEmpty()) {
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700578 mOutgoingConnectionServiceRpc.addConnectionServiceAdapter(mServant.getStub(),
579 null /*Session.Info*/);
Ihab Awad8aecfed2014-08-08 17:06:11 -0700580 }
581 RemoteConnection connection =
Ihab Awadb8e85c72014-08-23 20:34:57 -0700582 new RemoteConnection(id, mOutgoingConnectionServiceRpc, newRequest);
Ihab Awad8aecfed2014-08-08 17:06:11 -0700583 mPendingConnections.add(connection);
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700584 mConnectionById.put(id, connection);
Ihab Awadb8e85c72014-08-23 20:34:57 -0700585 mOutgoingConnectionServiceRpc.createConnection(
Ihab Awad5d0410f2014-07-30 10:07:40 -0700586 connectionManagerPhoneAccount,
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700587 id,
Ihab Awad5d0410f2014-07-30 10:07:40 -0700588 newRequest,
Yorke Leec3cf9822014-10-02 09:38:39 -0700589 isIncoming,
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700590 false /* isUnknownCall */,
591 null /*Session.info*/);
Andrew Lee100e2932014-09-08 15:34:24 -0700592 connection.registerCallback(new RemoteConnection.Callback() {
Ihab Awad8aecfed2014-08-08 17:06:11 -0700593 @Override
594 public void onDestroyed(RemoteConnection connection) {
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700595 mConnectionById.remove(id);
Ihab Awadb8e85c72014-08-23 20:34:57 -0700596 maybeDisconnectAdapter();
Ihab Awad8aecfed2014-08-08 17:06:11 -0700597 }
598 });
Ihab Awad5d0410f2014-07-30 10:07:40 -0700599 return connection;
600 } catch (RemoteException e) {
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700601 return RemoteConnection.failure(
602 new DisconnectCause(DisconnectCause.ERROR, e.toString()));
Santos Cordon52d8a152014-06-17 19:08:45 -0700603 }
604 }
605
Grace Jia9a09c672020-08-04 12:52:09 -0700606 RemoteConference createRemoteConference(
607 PhoneAccountHandle connectionManagerPhoneAccount,
608 ConnectionRequest request,
609 boolean isIncoming) {
610 final String id = UUID.randomUUID().toString();
611 try {
612 if (mConferenceById.isEmpty()) {
613 mOutgoingConnectionServiceRpc.addConnectionServiceAdapter(mServant.getStub(),
614 null /*Session.Info*/);
615 }
616 RemoteConference conference = new RemoteConference(id, mOutgoingConnectionServiceRpc);
617 mOutgoingConnectionServiceRpc.createConference(connectionManagerPhoneAccount,
618 id,
619 request,
620 isIncoming,
621 false /* isUnknownCall */,
622 null /*Session.info*/);
623 conference.registerCallback(new RemoteConference.Callback() {
624 @Override
625 public void onDestroyed(RemoteConference conference) {
626 mConferenceById.remove(id);
627 maybeDisconnectAdapter();
628 }
629 });
630 conference.putExtras(request.getExtras());
631 return conference;
632 } catch (RemoteException e) {
633 return RemoteConference.failure(
634 new DisconnectCause(DisconnectCause.ERROR, e.toString()));
635 }
636 }
637
Ihab Awad50e35062014-09-30 09:17:03 -0700638 private boolean hasConnection(String callId) {
mike dooley879142b2014-10-08 13:39:28 -0700639 return mConnectionById.containsKey(callId);
Ihab Awad50e35062014-09-30 09:17:03 -0700640 }
641
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700642 private RemoteConnection findConnectionForAction(
643 String callId, String action) {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700644 if (mConnectionById.containsKey(callId)) {
645 return mConnectionById.get(callId);
646 }
647 Log.w(this, "%s - Cannot find Connection %s", action, callId);
648 return NULL_CONNECTION;
Santos Cordon52d8a152014-06-17 19:08:45 -0700649 }
Ihab Awadb8e85c72014-08-23 20:34:57 -0700650
651 private RemoteConference findConferenceForAction(
652 String callId, String action) {
653 if (mConferenceById.containsKey(callId)) {
654 return mConferenceById.get(callId);
655 }
656 Log.w(this, "%s - Cannot find Conference %s", action, callId);
657 return NULL_CONFERENCE;
658 }
659
660 private void maybeDisconnectAdapter() {
661 if (mConnectionById.isEmpty() && mConferenceById.isEmpty()) {
662 try {
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700663 mOutgoingConnectionServiceRpc.removeConnectionServiceAdapter(mServant.getStub(),
664 null /*Session.info*/);
Ihab Awadb8e85c72014-08-23 20:34:57 -0700665 } catch (RemoteException e) {
666 }
667 }
668 }
Santos Cordon52d8a152014-06-17 19:08:45 -0700669}