blob: 8b503f2b97e4c4495269cd23e3410b3257fb52de [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;
Junhoedf3d822022-11-24 09:26:37 +000024import android.os.ResultReceiver;
Brad Ebinger4d75bee2016-10-28 12:29:55 -070025import android.telecom.Logging.Session;
Santos Cordon52d8a152014-06-17 19:08:45 -070026
Tyler Gunnef9f6f92014-09-12 22:16:17 -070027import com.android.internal.telecom.IConnectionService;
28import com.android.internal.telecom.IConnectionServiceAdapter;
29import com.android.internal.telecom.IVideoProvider;
30import com.android.internal.telecom.RemoteServiceCallback;
Pranav Madapurmathd8bb7782024-02-01 00:06:13 -080031import com.android.server.telecom.flags.FeatureFlags;
32import com.android.server.telecom.flags.FeatureFlagsImpl;
Santos Cordon52d8a152014-06-17 19:08:45 -070033
Ihab Awadb8e85c72014-08-23 20:34:57 -070034import java.util.ArrayList;
Ihab Awad5d0410f2014-07-30 10:07:40 -070035import java.util.HashMap;
36import java.util.HashSet;
Grace Jia9a09c672020-08-04 12:52:09 -070037import java.util.List;
Ihab Awad5d0410f2014-07-30 10:07:40 -070038import java.util.Map;
39import java.util.Set;
Santos Cordon52d8a152014-06-17 19:08:45 -070040import java.util.UUID;
41
42/**
43 * Remote connection service which other connection services can use to place calls on their behalf.
Sailesh Nepal091768c2014-06-30 15:15:23 -070044 *
45 * @hide
Santos Cordon52d8a152014-06-17 19:08:45 -070046 */
Ihab Awad5d0410f2014-07-30 10:07:40 -070047final class RemoteConnectionService {
Sailesh Nepal48031592014-07-18 14:21:23 -070048
Tyler Gunn4a57b9b2014-10-30 14:27:48 -070049 // Note: Casting null to avoid ambiguous constructor reference.
Ihab Awadb8e85c72014-08-23 20:34:57 -070050 private static final RemoteConnection NULL_CONNECTION =
Tyler Gunn4a57b9b2014-10-30 14:27:48 -070051 new RemoteConnection("NULL", null, (ConnectionRequest) null);
Ihab Awadb8e85c72014-08-23 20:34:57 -070052
53 private static final RemoteConference NULL_CONFERENCE =
54 new RemoteConference("NULL", null);
Santos Cordon52d8a152014-06-17 19:08:45 -070055
Ihab Awad5d0410f2014-07-30 10:07:40 -070056 private final IConnectionServiceAdapter mServantDelegate = new IConnectionServiceAdapter() {
Sailesh Nepal48031592014-07-18 14:21:23 -070057 @Override
Ihab Awad6107bab2014-08-18 09:23:25 -070058 public void handleCreateConnectionComplete(
Ihab Awadb19a0bc2014-08-07 19:46:01 -070059 String id,
60 ConnectionRequest request,
Brad Ebinger4d75bee2016-10-28 12:29:55 -070061 ParcelableConnection parcel,
62 Session.Info info) {
Ihab Awadb19a0bc2014-08-07 19:46:01 -070063 RemoteConnection connection =
64 findConnectionForAction(id, "handleCreateConnectionSuccessful");
Ihab Awad5d0410f2014-07-30 10:07:40 -070065 if (connection != NULL_CONNECTION && mPendingConnections.contains(connection)) {
66 mPendingConnections.remove(connection);
Ihab Awad6107bab2014-08-18 09:23:25 -070067 // Unconditionally initialize the connection ...
Ihab Awad5c9c86e2014-11-12 13:41:16 -080068 connection.setConnectionCapabilities(parcel.getConnectionCapabilities());
Tyler Gunn720c6642016-03-22 09:02:47 -070069 connection.setConnectionProperties(parcel.getConnectionProperties());
Sailesh Nepal2d3ced72015-01-31 20:17:35 -080070 if (parcel.getHandle() != null
71 || parcel.getState() != Connection.STATE_DISCONNECTED) {
72 connection.setAddress(parcel.getHandle(), parcel.getHandlePresentation());
73 }
74 if (parcel.getCallerDisplayName() != null
75 || parcel.getState() != Connection.STATE_DISCONNECTED) {
76 connection.setCallerDisplayName(
77 parcel.getCallerDisplayName(),
78 parcel.getCallerDisplayNamePresentation());
79 }
Sailesh Nepal70638f12014-09-09 21:49:14 -070080 // Set state after handle so that the client can identify the connection.
Sailesh Nepalc2a978d2014-09-20 18:23:05 -070081 if (parcel.getState() == Connection.STATE_DISCONNECTED) {
82 connection.setDisconnected(parcel.getDisconnectCause());
83 } else {
84 connection.setState(parcel.getState());
85 }
Ihab Awadb8e85c72014-08-23 20:34:57 -070086 List<RemoteConnection> conferenceable = new ArrayList<>();
87 for (String confId : parcel.getConferenceableConnectionIds()) {
88 if (mConnectionById.containsKey(confId)) {
89 conferenceable.add(mConnectionById.get(confId));
90 }
91 }
92 connection.setConferenceableConnections(conferenceable);
Ihab Awada64627c2014-08-20 09:36:40 -070093 connection.setVideoState(parcel.getVideoState());
Ihab Awad6107bab2014-08-18 09:23:25 -070094 if (connection.getState() == Connection.STATE_DISCONNECTED) {
95 // ... then, if it was created in a disconnected state, that indicates
96 // failure on the providing end, so immediately mark it destroyed
97 connection.setDestroyed();
98 }
Tyler Gunn31f0e0b2018-02-13 08:39:45 -080099 connection.setStatusHints(parcel.getStatusHints());
100 connection.setIsVoipAudioMode(parcel.getIsVoipAudioMode());
101 connection.setRingbackRequested(parcel.isRingbackRequested());
102 connection.putExtras(parcel.getExtras());
Sailesh Nepal48031592014-07-18 14:21:23 -0700103 }
104 }
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -0700105
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700106 @Override
Ravi Paluri80aa2142019-12-02 11:57:37 +0530107 public void handleCreateConferenceComplete(
108 String id,
109 ConnectionRequest request,
110 ParcelableConference parcel,
111 Session.Info info) {
112 }
113
114 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700115 public void setActive(String callId, Session.Info sessionInfo) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700116 if (mConnectionById.containsKey(callId)) {
117 findConnectionForAction(callId, "setActive")
118 .setState(Connection.STATE_ACTIVE);
119 } else {
120 findConferenceForAction(callId, "setActive")
121 .setState(Connection.STATE_ACTIVE);
122 }
Santos Cordon52d8a152014-06-17 19:08:45 -0700123 }
124
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700125 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700126 public void setRinging(String callId, Session.Info sessionInfo) {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700127 findConnectionForAction(callId, "setRinging")
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700128 .setState(Connection.STATE_RINGING);
Andrew Lee5ffbe8b82014-06-20 16:29:33 -0700129 }
130
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700131 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700132 public void setDialing(String callId, Session.Info sessionInfo) {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700133 findConnectionForAction(callId, "setDialing")
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700134 .setState(Connection.STATE_DIALING);
Santos Cordon52d8a152014-06-17 19:08:45 -0700135 }
136
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700137 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700138 public void setPulling(String callId, Session.Info sessionInfo) {
Tyler Gunnc96b5e02016-07-07 22:53:57 -0700139 findConnectionForAction(callId, "setPulling")
140 .setState(Connection.STATE_PULLING_CALL);
141 }
142
143 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700144 public void setDisconnected(String callId, DisconnectCause disconnectCause,
145 Session.Info sessionInfo) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700146 if (mConnectionById.containsKey(callId)) {
147 findConnectionForAction(callId, "setDisconnected")
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700148 .setDisconnected(disconnectCause);
Ihab Awadb8e85c72014-08-23 20:34:57 -0700149 } else {
150 findConferenceForAction(callId, "setDisconnected")
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700151 .setDisconnected(disconnectCause);
Ihab Awadb8e85c72014-08-23 20:34:57 -0700152 }
Santos Cordon52d8a152014-06-17 19:08:45 -0700153 }
154
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700155 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700156 public void setOnHold(String callId, Session.Info sessionInfo) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700157 if (mConnectionById.containsKey(callId)) {
158 findConnectionForAction(callId, "setOnHold")
159 .setState(Connection.STATE_HOLDING);
160 } else {
161 findConferenceForAction(callId, "setOnHold")
162 .setState(Connection.STATE_HOLDING);
163 }
Santos Cordon52d8a152014-06-17 19:08:45 -0700164 }
165
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700166 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700167 public void setRingbackRequested(String callId, boolean ringing, Session.Info sessionInfo) {
Andrew Lee100e2932014-09-08 15:34:24 -0700168 findConnectionForAction(callId, "setRingbackRequested")
169 .setRingbackRequested(ringing);
Santos Cordon52d8a152014-06-17 19:08:45 -0700170 }
171
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700172 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700173 public void setConnectionCapabilities(String callId, int connectionCapabilities,
174 Session.Info sessionInfo) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700175 if (mConnectionById.containsKey(callId)) {
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800176 findConnectionForAction(callId, "setConnectionCapabilities")
177 .setConnectionCapabilities(connectionCapabilities);
Ihab Awadb8e85c72014-08-23 20:34:57 -0700178 } else {
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800179 findConferenceForAction(callId, "setConnectionCapabilities")
180 .setConnectionCapabilities(connectionCapabilities);
Ihab Awadb8e85c72014-08-23 20:34:57 -0700181 }
Santos Cordon52d8a152014-06-17 19:08:45 -0700182 }
183
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700184 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700185 public void setConnectionProperties(String callId, int connectionProperties,
186 Session.Info sessionInfo) {
Tyler Gunn720c6642016-03-22 09:02:47 -0700187 if (mConnectionById.containsKey(callId)) {
188 findConnectionForAction(callId, "setConnectionProperties")
189 .setConnectionProperties(connectionProperties);
190 } else {
191 findConferenceForAction(callId, "setConnectionProperties")
192 .setConnectionProperties(connectionProperties);
193 }
194 }
195
196 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700197 public void setIsConferenced(String callId, String conferenceCallId,
198 Session.Info sessionInfo) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700199 // Note: callId should not be null; conferenceCallId may be null
200 RemoteConnection connection =
201 findConnectionForAction(callId, "setIsConferenced");
202 if (connection != NULL_CONNECTION) {
203 if (conferenceCallId == null) {
204 // 'connection' is being split from its conference
205 if (connection.getConference() != null) {
206 connection.getConference().removeConnection(connection);
207 }
208 } else {
209 RemoteConference conference =
210 findConferenceForAction(conferenceCallId, "setIsConferenced");
211 if (conference != NULL_CONFERENCE) {
212 conference.addConnection(connection);
213 }
214 }
215 }
Santos Cordon52d8a152014-06-17 19:08:45 -0700216 }
217
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700218 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700219 public void setConferenceMergeFailed(String callId, Session.Info sessionInfo) {
Anthony Lee17455a32015-04-24 15:25:29 -0700220 // Nothing to do here.
221 // The event has already been handled and there is no state to update
222 // in the underlying connection or conference objects
223 }
224
225 @Override
Srikanth Chintalafcb15012017-05-04 20:58:34 +0530226 public void onPhoneAccountChanged(String callId, PhoneAccountHandle pHandle,
227 Session.Info sessionInfo) {
228 }
229
230 @Override
Pengquan Meng63d25a52017-11-21 18:01:13 -0800231 public void onConnectionServiceFocusReleased(Session.Info sessionInfo) {}
232
233 @Override
Ihab Awadb8e85c72014-08-23 20:34:57 -0700234 public void addConferenceCall(
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700235 final String callId, ParcelableConference parcel, Session.Info sessionInfo) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700236 RemoteConference conference = new RemoteConference(callId,
237 mOutgoingConnectionServiceRpc);
238
239 for (String id : parcel.getConnectionIds()) {
240 RemoteConnection c = mConnectionById.get(id);
241 if (c != null) {
242 conference.addConnection(c);
243 }
244 }
Tyler Gunn2d4fcc12021-06-24 11:25:07 -0700245 // We used to skip adding empty conferences; however in the world of IMS conference
246 // calls we need to add them to the remote connection service because they will always
247 // start with no participants.
Ihab Awadb8e85c72014-08-23 20:34:57 -0700248
249 conference.setState(parcel.getState());
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800250 conference.setConnectionCapabilities(parcel.getConnectionCapabilities());
Tyler Gunn04ce7572016-08-15 10:56:12 -0700251 conference.setConnectionProperties(parcel.getConnectionProperties());
Tyler Gunncd6ccfd2016-10-17 15:48:19 -0700252 conference.putExtras(parcel.getExtras());
Ihab Awadb8e85c72014-08-23 20:34:57 -0700253 mConferenceById.put(callId, conference);
Tyler Gunncd6ccfd2016-10-17 15:48:19 -0700254
255 // Stash the original connection ID as it exists in the source ConnectionService.
256 // Telecom will use this to avoid adding duplicates later.
257 // See comments on Connection.EXTRA_ORIGINAL_CONNECTION_ID for more information.
258 Bundle newExtras = new Bundle();
259 newExtras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
Tyler Gunnc59fd0c2020-04-17 14:03:35 -0700260 // Track the fact this request was relayed through the remote connection service.
261 newExtras.putParcelable(Connection.EXTRA_REMOTE_PHONE_ACCOUNT_HANDLE,
262 parcel.getPhoneAccount());
Tyler Gunncd6ccfd2016-10-17 15:48:19 -0700263 conference.putExtras(newExtras);
264
Andrew Lee100e2932014-09-08 15:34:24 -0700265 conference.registerCallback(new RemoteConference.Callback() {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700266 @Override
267 public void onDestroyed(RemoteConference c) {
268 mConferenceById.remove(callId);
269 maybeDisconnectAdapter();
270 }
271 });
272
273 mOurConnectionServiceImpl.addRemoteConference(conference);
Santos Cordon52d8a152014-06-17 19:08:45 -0700274 }
275
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700276 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700277 public void removeCall(String callId, Session.Info sessionInfo) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700278 if (mConnectionById.containsKey(callId)) {
279 findConnectionForAction(callId, "removeCall")
280 .setDestroyed();
281 } else {
282 findConferenceForAction(callId, "removeCall")
283 .setDestroyed();
284 }
Santos Cordon52d8a152014-06-17 19:08:45 -0700285 }
286
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700287 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700288 public void onPostDialWait(String callId, String remaining, Session.Info sessionInfo) {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700289 findConnectionForAction(callId, "onPostDialWait")
290 .setPostDialWait(remaining);
Santos Cordon52d8a152014-06-17 19:08:45 -0700291 }
292
Santos Cordon52d8a152014-06-17 19:08:45 -0700293 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700294 public void onPostDialChar(String callId, char nextChar, Session.Info sessionInfo) {
Nancy Chen27d1c2d2014-12-15 16:12:50 -0800295 findConnectionForAction(callId, "onPostDialChar")
296 .onPostDialChar(nextChar);
297 }
298
299 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700300 public void queryRemoteConnectionServices(RemoteServiceCallback callback,
Tyler Gunn4c69fb32019-05-17 10:49:16 -0700301 String callingPackage, Session.Info sessionInfo) {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700302 // Not supported from remote connection service.
Santos Cordon52d8a152014-06-17 19:08:45 -0700303 }
Tyler Gunn8d83fa92014-07-01 11:31:21 -0700304
Sailesh Nepal33aaae42014-07-07 22:49:44 -0700305 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700306 public void setVideoProvider(String callId, IVideoProvider videoProvider,
307 Session.Info sessionInfo) {
Tyler Gunnbf9c6fd2016-11-09 10:19:23 -0800308
309 String callingPackage = mOurConnectionServiceImpl.getApplicationContext()
310 .getOpPackageName();
Tyler Gunn159f35c2017-03-02 09:28:37 -0800311 int targetSdkVersion = mOurConnectionServiceImpl.getApplicationInfo().targetSdkVersion;
Sailesh Nepal11aeae52015-01-28 16:54:09 -0800312 RemoteConnection.VideoProvider remoteVideoProvider = null;
313 if (videoProvider != null) {
Tyler Gunnbf9c6fd2016-11-09 10:19:23 -0800314 remoteVideoProvider = new RemoteConnection.VideoProvider(videoProvider,
Tyler Gunn159f35c2017-03-02 09:28:37 -0800315 callingPackage, targetSdkVersion);
Sailesh Nepal11aeae52015-01-28 16:54:09 -0800316 }
Ihab Awada64627c2014-08-20 09:36:40 -0700317 findConnectionForAction(callId, "setVideoProvider")
Sailesh Nepal11aeae52015-01-28 16:54:09 -0800318 .setVideoProvider(remoteVideoProvider);
Tyler Gunnaa07df82014-07-17 07:50:22 -0700319 }
320
321 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700322 public void setVideoState(String callId, int videoState, Session.Info sessionInfo) {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700323 findConnectionForAction(callId, "setVideoState")
324 .setVideoState(videoState);
Sailesh Nepal33aaae42014-07-07 22:49:44 -0700325 }
Sailesh Nepale7ef59a2014-07-08 21:48:22 -0700326
Sailesh Nepale7ef59a2014-07-08 21:48:22 -0700327 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700328 public void setIsVoipAudioMode(String callId, boolean isVoip, Session.Info sessionInfo) {
Andrew Lee100e2932014-09-08 15:34:24 -0700329 findConnectionForAction(callId, "setIsVoipAudioMode")
330 .setIsVoipAudioMode(isVoip);
Sailesh Nepale7ef59a2014-07-08 21:48:22 -0700331 }
Sailesh Nepal61203862014-07-11 14:50:13 -0700332
333 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700334 public void setStatusHints(String callId, StatusHints statusHints,
335 Session.Info sessionInfo) {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700336 findConnectionForAction(callId, "setStatusHints")
337 .setStatusHints(statusHints);
Sailesh Nepal61203862014-07-11 14:50:13 -0700338 }
339
340 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700341 public void setAddress(String callId, Uri address, int presentation,
342 Session.Info sessionInfo) {
Andrew Lee100e2932014-09-08 15:34:24 -0700343 findConnectionForAction(callId, "setAddress")
344 .setAddress(address, presentation);
Sailesh Nepal61203862014-07-11 14:50:13 -0700345 }
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -0700346
347 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -0700348 public void setCallerDisplayName(String callId, String callerDisplayName,
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700349 int presentation, Session.Info sessionInfo) {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700350 findConnectionForAction(callId, "setCallerDisplayName")
351 .setCallerDisplayName(callerDisplayName, presentation);
352 }
353
354 @Override
Ihab Awad5d0410f2014-07-30 10:07:40 -0700355 public IBinder asBinder() {
356 throw new UnsupportedOperationException();
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -0700357 }
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700358
359 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700360 public final void setConferenceableConnections(String callId,
361 List<String> conferenceableConnectionIds, Session.Info sessionInfo) {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700362 List<RemoteConnection> conferenceable = new ArrayList<>();
363 for (String id : conferenceableConnectionIds) {
364 if (mConnectionById.containsKey(id)) {
365 conferenceable.add(mConnectionById.get(id));
366 }
367 }
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700368
Ihab Awad50e35062014-09-30 09:17:03 -0700369 if (hasConnection(callId)) {
370 findConnectionForAction(callId, "setConferenceableConnections")
371 .setConferenceableConnections(conferenceable);
372 } else {
373 findConferenceForAction(callId, "setConferenceableConnections")
374 .setConferenceableConnections(conferenceable);
375 }
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700376 }
Tyler Gunn4a57b9b2014-10-30 14:27:48 -0700377
378 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700379 public void addExistingConnection(String callId, ParcelableConnection connection,
380 Session.Info sessionInfo) {
Tyler Gunn2d4fcc12021-06-24 11:25:07 -0700381 Log.i(RemoteConnectionService.this, "addExistingConnection: callId=%s, conn=%s", callId,
382 connection);
Tyler Gunnbf9c6fd2016-11-09 10:19:23 -0800383 String callingPackage = mOurConnectionServiceImpl.getApplicationContext().
384 getOpPackageName();
Tyler Gunn159f35c2017-03-02 09:28:37 -0800385 int callingTargetSdkVersion = mOurConnectionServiceImpl.getApplicationInfo()
386 .targetSdkVersion;
Tyler Gunncd6ccfd2016-10-17 15:48:19 -0700387 RemoteConnection remoteConnection = new RemoteConnection(callId,
Tyler Gunn159f35c2017-03-02 09:28:37 -0800388 mOutgoingConnectionServiceRpc, connection, callingPackage,
389 callingTargetSdkVersion);
Tyler Gunnc59fd0c2020-04-17 14:03:35 -0700390 // Track that it is via a remote connection.
391 Bundle newExtras = new Bundle();
392 newExtras.putParcelable(Connection.EXTRA_REMOTE_PHONE_ACCOUNT_HANDLE,
393 connection.getPhoneAccount());
Tyler Gunn2d4fcc12021-06-24 11:25:07 -0700394 if (connection.getParentCallId() != null) {
395 RemoteConference parentConf = mConferenceById.get(connection.getParentCallId());
396 // If there is a parent being set, we need to stash the conference ID here.
397 // Telephony can add an existing connection while specifying a parent conference.
398 // There is no equivalent version of that operation as part of the remote connection
399 // API, so we will stash the pre-defined parent's ID in the extras. When the
400 // connectionmanager copies over the extras from the remote connection to the
401 // actual one, it'll get passed to Telecom so that it can make the association.
402 if (parentConf != null) {
403 newExtras.putString(Connection.EXTRA_ADD_TO_CONFERENCE_ID, parentConf.getId());
404 Log.i(this, "addExistingConnection: stash parent of %s as %s",
405 connection.getParentCallId(), parentConf.getId());
406 }
407 }
Tyler Gunnc59fd0c2020-04-17 14:03:35 -0700408 remoteConnection.putExtras(newExtras);
Tyler Gunncd6ccfd2016-10-17 15:48:19 -0700409 mConnectionById.put(callId, remoteConnection);
410 remoteConnection.registerCallback(new RemoteConnection.Callback() {
411 @Override
412 public void onDestroyed(RemoteConnection connection) {
413 mConnectionById.remove(callId);
414 maybeDisconnectAdapter();
415 }
416 });
417 mOurConnectionServiceImpl.addRemoteExistingConnection(remoteConnection);
Tyler Gunn4a57b9b2014-10-30 14:27:48 -0700418 }
Santos Cordon6b7f9552015-05-27 17:21:45 -0700419
420 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700421 public void putExtras(String callId, Bundle extras, Session.Info sessionInfo) {
Tyler Gunndee56a82016-03-23 16:06:34 -0700422 if (hasConnection(callId)) {
423 findConnectionForAction(callId, "putExtras").putExtras(extras);
Santos Cordon6b7f9552015-05-27 17:21:45 -0700424 } else {
Tyler Gunndee56a82016-03-23 16:06:34 -0700425 findConferenceForAction(callId, "putExtras").putExtras(extras);
426 }
427 }
428
429 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700430 public void removeExtras(String callId, List<String> keys, Session.Info sessionInfo) {
Tyler Gunndee56a82016-03-23 16:06:34 -0700431 if (hasConnection(callId)) {
432 findConnectionForAction(callId, "removeExtra").removeExtras(keys);
433 } else {
434 findConferenceForAction(callId, "removeExtra").removeExtras(keys);
Santos Cordon6b7f9552015-05-27 17:21:45 -0700435 }
436 }
Tyler Gunnbd1eb1f2016-02-16 14:36:20 -0800437
438 @Override
Hall Liua98f58b52017-11-07 17:59:28 -0800439 public void setAudioRoute(String callId, int audioRoute, String bluetoothAddress,
440 Session.Info sessionInfo) {
Tyler Gunnf5035432017-01-09 09:43:12 -0800441 if (hasConnection(callId)) {
442 // TODO(3pcalls): handle this for remote connections.
443 // Likely we don't want to do anything since it doesn't make sense for self-managed
444 // connections to go through a connection mgr.
445 }
446 }
447
448 @Override
Brad Ebinger4d75bee2016-10-28 12:29:55 -0700449 public void onConnectionEvent(String callId, String event, Bundle extras,
450 Session.Info sessionInfo) {
Tyler Gunnbd1eb1f2016-02-16 14:36:20 -0800451 if (mConnectionById.containsKey(callId)) {
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700452 findConnectionForAction(callId, "onConnectionEvent").onConnectionEvent(event,
453 extras);
Tyler Gunnbd1eb1f2016-02-16 14:36:20 -0800454 }
455 }
Hall Liu57006aa2017-02-06 10:49:48 -0800456
457 @Override
458 public void onRttInitiationSuccess(String callId, Session.Info sessionInfo)
459 throws RemoteException {
460 if (hasConnection(callId)) {
461 findConnectionForAction(callId, "onRttInitiationSuccess")
462 .onRttInitiationSuccess();
463 } else {
464 Log.w(this, "onRttInitiationSuccess called on a remote conference");
465 }
466 }
467
468 @Override
469 public void onRttInitiationFailure(String callId, int reason, Session.Info sessionInfo)
470 throws RemoteException {
471 if (hasConnection(callId)) {
472 findConnectionForAction(callId, "onRttInitiationFailure")
473 .onRttInitiationFailure(reason);
474 } else {
475 Log.w(this, "onRttInitiationFailure called on a remote conference");
476 }
477 }
478
479 @Override
480 public void onRttSessionRemotelyTerminated(String callId, Session.Info sessionInfo)
481 throws RemoteException {
482 if (hasConnection(callId)) {
483 findConnectionForAction(callId, "onRttSessionRemotelyTerminated")
484 .onRttSessionRemotelyTerminated();
485 } else {
486 Log.w(this, "onRttSessionRemotelyTerminated called on a remote conference");
487 }
488 }
489
490 @Override
491 public void onRemoteRttRequest(String callId, Session.Info sessionInfo)
492 throws RemoteException {
493 if (hasConnection(callId)) {
494 findConnectionForAction(callId, "onRemoteRttRequest")
495 .onRemoteRttRequest();
496 } else {
497 Log.w(this, "onRemoteRttRequest called on a remote conference");
498 }
499 }
Mengjun Leng25707742017-07-04 11:10:37 +0800500
501 @Override
502 public void resetConnectionTime(String callId, Session.Info sessionInfo) {
503 // Do nothing
504 }
Tyler Gunn68a73a42018-10-03 15:38:57 -0700505
506 @Override
507 public void setConferenceState(String callId, boolean isConference,
508 Session.Info sessionInfo) {
509 // Do nothing
510 }
Brad Ebingere0c12f42020-04-08 16:25:12 -0700511
512 @Override
513 public void setCallDirection(String callId, int direction, Session.Info sessionInfo) {
514 // Do nothing
515 }
Junhoedf3d822022-11-24 09:26:37 +0000516
517 @Override
518 public void requestCallEndpointChange(String callId, CallEndpoint endpoint,
519 ResultReceiver callback, Session.Info sessionInfo) {
520 // Do nothing
521 }
yongnamcha8ec56242022-11-28 06:23:02 +0000522
523 @Override
524 public void queryLocation(String callId, long timeoutMillis, String provider,
525 ResultReceiver callback, Session.Info sessionInfo) {
526 // Do nothing
527 }
Santos Cordon52d8a152014-06-17 19:08:45 -0700528 };
529
Ihab Awad5d0410f2014-07-30 10:07:40 -0700530 private final ConnectionServiceAdapterServant mServant =
531 new ConnectionServiceAdapterServant(mServantDelegate);
Santos Cordon52d8a152014-06-17 19:08:45 -0700532
Ihab Awad5d0410f2014-07-30 10:07:40 -0700533 private final DeathRecipient mDeathRecipient = new DeathRecipient() {
534 @Override
535 public void binderDied() {
536 for (RemoteConnection c : mConnectionById.values()) {
537 c.setDestroyed();
538 }
Ihab Awadb8e85c72014-08-23 20:34:57 -0700539 for (RemoteConference c : mConferenceById.values()) {
540 c.setDestroyed();
541 }
Ihab Awad5d0410f2014-07-30 10:07:40 -0700542 mConnectionById.clear();
Ihab Awadb8e85c72014-08-23 20:34:57 -0700543 mConferenceById.clear();
Ihab Awad5d0410f2014-07-30 10:07:40 -0700544 mPendingConnections.clear();
Ihab Awadb8e85c72014-08-23 20:34:57 -0700545 mOutgoingConnectionServiceRpc.asBinder().unlinkToDeath(mDeathRecipient, 0);
Ihab Awad5d0410f2014-07-30 10:07:40 -0700546 }
547 };
548
Ihab Awadb8e85c72014-08-23 20:34:57 -0700549 private final IConnectionService mOutgoingConnectionServiceRpc;
550 private final ConnectionService mOurConnectionServiceImpl;
Ihab Awad5d0410f2014-07-30 10:07:40 -0700551 private final Map<String, RemoteConnection> mConnectionById = new HashMap<>();
Ihab Awadb8e85c72014-08-23 20:34:57 -0700552 private final Map<String, RemoteConference> mConferenceById = new HashMap<>();
Ihab Awad5d0410f2014-07-30 10:07:40 -0700553 private final Set<RemoteConnection> mPendingConnections = new HashSet<>();
554
Pranav Madapurmathd8bb7782024-02-01 00:06:13 -0800555 /** Telecom feature flags **/
556 private final FeatureFlags mTelecomFeatureFlags = new FeatureFlagsImpl();
557
Ihab Awadb8e85c72014-08-23 20:34:57 -0700558 RemoteConnectionService(
559 IConnectionService outgoingConnectionServiceRpc,
560 ConnectionService ourConnectionServiceImpl) throws RemoteException {
561 mOutgoingConnectionServiceRpc = outgoingConnectionServiceRpc;
562 mOutgoingConnectionServiceRpc.asBinder().linkToDeath(mDeathRecipient, 0);
563 mOurConnectionServiceImpl = ourConnectionServiceImpl;
Santos Cordon52d8a152014-06-17 19:08:45 -0700564 }
565
566 @Override
567 public String toString() {
Ihab Awadb8e85c72014-08-23 20:34:57 -0700568 return "[RemoteCS - " + mOutgoingConnectionServiceRpc.asBinder().toString() + "]";
Santos Cordon52d8a152014-06-17 19:08:45 -0700569 }
570
Ihab Awadf8b69882014-07-25 15:14:01 -0700571 final RemoteConnection createRemoteConnection(
572 PhoneAccountHandle connectionManagerPhoneAccount,
573 ConnectionRequest request,
574 boolean isIncoming) {
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700575 final String id = UUID.randomUUID().toString();
Tyler Gunnc59fd0c2020-04-17 14:03:35 -0700576 Bundle extras = new Bundle();
577 if (request.getExtras() != null) {
578 extras.putAll(request.getExtras());
579 }
580 // We will set the package name for the originator of the remote request; this lets the
581 // receiving ConnectionService know that the request originated from a remote connection
582 // service so that it can provide tracking information for Telecom.
583 extras.putString(Connection.EXTRA_REMOTE_CONNECTION_ORIGINATING_PACKAGE_NAME,
584 mOurConnectionServiceImpl.getApplicationContext().getOpPackageName());
585
Pranav Madapurmathd8bb7782024-02-01 00:06:13 -0800586 // Defaulted ConnectionRequest params
587 String telecomCallId = "";
588 boolean shouldShowIncomingUI = false;
589 if (mTelecomFeatureFlags.setRemoteConnectionCallId()) {
590 telecomCallId = id;
591 shouldShowIncomingUI = request.shouldShowIncomingCallUi();
592 }
593
Hall Liu95d55872017-01-25 17:12:49 -0800594 final ConnectionRequest newRequest = new ConnectionRequest.Builder()
595 .setAccountHandle(request.getAccountHandle())
596 .setAddress(request.getAddress())
Tyler Gunnc59fd0c2020-04-17 14:03:35 -0700597 .setExtras(extras)
Hall Liu95d55872017-01-25 17:12:49 -0800598 .setVideoState(request.getVideoState())
599 .setRttPipeFromInCall(request.getRttPipeFromInCall())
600 .setRttPipeToInCall(request.getRttPipeToInCall())
Pranav Madapurmathd8bb7782024-02-01 00:06:13 -0800601 // Flagged changes
602 .setTelecomCallId(telecomCallId)
603 .setShouldShowIncomingCallUi(shouldShowIncomingUI)
Hall Liu95d55872017-01-25 17:12:49 -0800604 .build();
Ihab Awad5d0410f2014-07-30 10:07:40 -0700605 try {
Ihab Awad8aecfed2014-08-08 17:06:11 -0700606 if (mConnectionById.isEmpty()) {
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700607 mOutgoingConnectionServiceRpc.addConnectionServiceAdapter(mServant.getStub(),
608 null /*Session.Info*/);
Ihab Awad8aecfed2014-08-08 17:06:11 -0700609 }
610 RemoteConnection connection =
Ihab Awadb8e85c72014-08-23 20:34:57 -0700611 new RemoteConnection(id, mOutgoingConnectionServiceRpc, newRequest);
Ihab Awad8aecfed2014-08-08 17:06:11 -0700612 mPendingConnections.add(connection);
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700613 mConnectionById.put(id, connection);
Ihab Awadb8e85c72014-08-23 20:34:57 -0700614 mOutgoingConnectionServiceRpc.createConnection(
Ihab Awad5d0410f2014-07-30 10:07:40 -0700615 connectionManagerPhoneAccount,
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700616 id,
Ihab Awad5d0410f2014-07-30 10:07:40 -0700617 newRequest,
Yorke Leec3cf9822014-10-02 09:38:39 -0700618 isIncoming,
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700619 false /* isUnknownCall */,
620 null /*Session.info*/);
Andrew Lee100e2932014-09-08 15:34:24 -0700621 connection.registerCallback(new RemoteConnection.Callback() {
Ihab Awad8aecfed2014-08-08 17:06:11 -0700622 @Override
623 public void onDestroyed(RemoteConnection connection) {
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700624 mConnectionById.remove(id);
Ihab Awadb8e85c72014-08-23 20:34:57 -0700625 maybeDisconnectAdapter();
Ihab Awad8aecfed2014-08-08 17:06:11 -0700626 }
627 });
Ihab Awad5d0410f2014-07-30 10:07:40 -0700628 return connection;
629 } catch (RemoteException e) {
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700630 return RemoteConnection.failure(
631 new DisconnectCause(DisconnectCause.ERROR, e.toString()));
Santos Cordon52d8a152014-06-17 19:08:45 -0700632 }
633 }
634
Grace Jia9a09c672020-08-04 12:52:09 -0700635 RemoteConference createRemoteConference(
636 PhoneAccountHandle connectionManagerPhoneAccount,
637 ConnectionRequest request,
638 boolean isIncoming) {
639 final String id = UUID.randomUUID().toString();
640 try {
641 if (mConferenceById.isEmpty()) {
642 mOutgoingConnectionServiceRpc.addConnectionServiceAdapter(mServant.getStub(),
643 null /*Session.Info*/);
644 }
Pranav Madapurmathd8bb7782024-02-01 00:06:13 -0800645
646 // Set telecom call id to what's being tracked by base ConnectionService.
647 String telecomCallId = mTelecomFeatureFlags.setRemoteConnectionCallId()
648 ? id : request.getTelecomCallId();
649
650 final ConnectionRequest newRequest = new ConnectionRequest.Builder()
651 .setAccountHandle(request.getAccountHandle())
652 .setAddress(request.getAddress())
653 .setExtras(request.getExtras())
654 .setVideoState(request.getVideoState())
655 .setShouldShowIncomingCallUi(request.shouldShowIncomingCallUi())
656 .setRttPipeFromInCall(request.getRttPipeFromInCall())
657 .setRttPipeToInCall(request.getRttPipeToInCall())
658 .setParticipants(request.getParticipants())
659 .setIsAdhocConferenceCall(request.isAdhocConferenceCall())
660 .setTelecomCallId(telecomCallId)
661 .build();
662
Grace Jia9a09c672020-08-04 12:52:09 -0700663 RemoteConference conference = new RemoteConference(id, mOutgoingConnectionServiceRpc);
664 mOutgoingConnectionServiceRpc.createConference(connectionManagerPhoneAccount,
665 id,
Pranav Madapurmathd8bb7782024-02-01 00:06:13 -0800666 newRequest,
Grace Jia9a09c672020-08-04 12:52:09 -0700667 isIncoming,
668 false /* isUnknownCall */,
669 null /*Session.info*/);
670 conference.registerCallback(new RemoteConference.Callback() {
671 @Override
672 public void onDestroyed(RemoteConference conference) {
673 mConferenceById.remove(id);
674 maybeDisconnectAdapter();
675 }
676 });
Pranav Madapurmathd8bb7782024-02-01 00:06:13 -0800677 conference.putExtras(newRequest.getExtras());
Grace Jia9a09c672020-08-04 12:52:09 -0700678 return conference;
679 } catch (RemoteException e) {
680 return RemoteConference.failure(
681 new DisconnectCause(DisconnectCause.ERROR, e.toString()));
682 }
683 }
684
Ihab Awad50e35062014-09-30 09:17:03 -0700685 private boolean hasConnection(String callId) {
mike dooley879142b2014-10-08 13:39:28 -0700686 return mConnectionById.containsKey(callId);
Ihab Awad50e35062014-09-30 09:17:03 -0700687 }
688
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700689 private RemoteConnection findConnectionForAction(
690 String callId, String action) {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700691 if (mConnectionById.containsKey(callId)) {
692 return mConnectionById.get(callId);
693 }
694 Log.w(this, "%s - Cannot find Connection %s", action, callId);
695 return NULL_CONNECTION;
Santos Cordon52d8a152014-06-17 19:08:45 -0700696 }
Ihab Awadb8e85c72014-08-23 20:34:57 -0700697
698 private RemoteConference findConferenceForAction(
699 String callId, String action) {
700 if (mConferenceById.containsKey(callId)) {
701 return mConferenceById.get(callId);
702 }
703 Log.w(this, "%s - Cannot find Conference %s", action, callId);
704 return NULL_CONFERENCE;
705 }
706
707 private void maybeDisconnectAdapter() {
708 if (mConnectionById.isEmpty() && mConferenceById.isEmpty()) {
709 try {
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700710 mOutgoingConnectionServiceRpc.removeConnectionServiceAdapter(mServant.getStub(),
711 null /*Session.info*/);
Ihab Awadb8e85c72014-08-23 20:34:57 -0700712 } catch (RemoteException e) {
713 }
714 }
715 }
Santos Cordon52d8a152014-06-17 19:08:45 -0700716}