1 /* 2 * Copyright 2014, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.telecom; 18 19 import static android.Manifest.permission.MODIFY_PHONE_STATE; 20 21 import android.app.AppOpsManager; 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.pm.PackageManager; 25 import android.net.Uri; 26 import android.os.Binder; 27 import android.os.Bundle; 28 import android.os.IBinder; 29 import android.os.ParcelFileDescriptor; 30 import android.os.RemoteException; 31 import android.os.UserHandle; 32 import android.telecom.CallAudioState; 33 import android.telecom.Connection; 34 import android.telecom.ConnectionRequest; 35 import android.telecom.ConnectionService; 36 import android.telecom.DisconnectCause; 37 import android.telecom.GatewayInfo; 38 import android.telecom.Log; 39 import android.telecom.Logging.Session; 40 import android.telecom.ParcelableConference; 41 import android.telecom.ParcelableConnection; 42 import android.telecom.PhoneAccountHandle; 43 import android.telecom.StatusHints; 44 import android.telecom.TelecomManager; 45 import android.telecom.VideoProfile; 46 47 import com.android.internal.annotations.VisibleForTesting; 48 import com.android.internal.telecom.IConnectionService; 49 import com.android.internal.telecom.IConnectionServiceAdapter; 50 import com.android.internal.telecom.IVideoProvider; 51 import com.android.internal.telecom.RemoteServiceCallback; 52 import com.android.internal.util.Preconditions; 53 54 import java.util.ArrayList; 55 import java.util.Collections; 56 import java.util.HashMap; 57 import java.util.List; 58 import java.util.Map; 59 import java.util.Set; 60 import java.util.concurrent.ConcurrentHashMap; 61 62 /** 63 * Wrapper for {@link IConnectionService}s, handles binding to {@link IConnectionService} and keeps 64 * track of when the object can safely be unbound. Other classes should not use 65 * {@link IConnectionService} directly and instead should use this class to invoke methods of 66 * {@link IConnectionService}. 67 */ 68 @VisibleForTesting 69 public class ConnectionServiceWrapper extends ServiceBinder implements 70 ConnectionServiceFocusManager.ConnectionServiceFocus { 71 72 private static final String TELECOM_ABBREVIATION = "cast"; 73 74 private final class Adapter extends IConnectionServiceAdapter.Stub { 75 76 @Override handleCreateConnectionComplete(String callId, ConnectionRequest request, ParcelableConnection connection, Session.Info sessionInfo)77 public void handleCreateConnectionComplete(String callId, ConnectionRequest request, 78 ParcelableConnection connection, Session.Info sessionInfo) { 79 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_HANDLE_CREATE_CONNECTION_COMPLETE, 80 mPackageAbbreviation); 81 long token = Binder.clearCallingIdentity(); 82 try { 83 synchronized (mLock) { 84 logIncoming("handleCreateConnectionComplete %s", callId); 85 ConnectionServiceWrapper.this 86 .handleCreateConnectionComplete(callId, request, connection); 87 88 if (mServiceInterface != null) { 89 logOutgoing("createConnectionComplete %s", callId); 90 try { 91 mServiceInterface.createConnectionComplete(callId, 92 Log.getExternalSession()); 93 } catch (RemoteException e) { 94 } 95 } 96 } 97 } catch (Throwable t) { 98 Log.e(ConnectionServiceWrapper.this, t, ""); 99 throw t; 100 } finally { 101 Binder.restoreCallingIdentity(token); 102 Log.endSession(); 103 } 104 } 105 106 @Override handleCreateConferenceComplete(String callId, ConnectionRequest request, ParcelableConference conference, Session.Info sessionInfo)107 public void handleCreateConferenceComplete(String callId, ConnectionRequest request, 108 ParcelableConference conference, Session.Info sessionInfo) { 109 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_HANDLE_CREATE_CONNECTION_COMPLETE, 110 mPackageAbbreviation); 111 long token = Binder.clearCallingIdentity(); 112 try { 113 synchronized (mLock) { 114 logIncoming("handleCreateConferenceComplete %s", callId); 115 ConnectionServiceWrapper.this 116 .handleCreateConferenceComplete(callId, request, conference); 117 118 if (mServiceInterface != null) { 119 logOutgoing("createConferenceComplete %s", callId); 120 try { 121 mServiceInterface.createConferenceComplete(callId, 122 Log.getExternalSession()); 123 } catch (RemoteException e) { 124 } 125 } 126 } 127 } catch (Throwable t) { 128 Log.e(ConnectionServiceWrapper.this, t, ""); 129 throw t; 130 } finally { 131 Binder.restoreCallingIdentity(token); 132 Log.endSession(); 133 } 134 } 135 136 137 @Override setActive(String callId, Session.Info sessionInfo)138 public void setActive(String callId, Session.Info sessionInfo) { 139 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_ACTIVE, 140 mPackageAbbreviation); 141 long token = Binder.clearCallingIdentity(); 142 try { 143 synchronized (mLock) { 144 logIncoming("setActive %s", callId); 145 Call call = mCallIdMapper.getCall(callId); 146 if (call != null) { 147 mCallsManager.markCallAsActive(call); 148 } else { 149 // Log.w(this, "setActive, unknown call id: %s", msg.obj); 150 } 151 } 152 } catch (Throwable t) { 153 Log.e(ConnectionServiceWrapper.this, t, ""); 154 throw t; 155 } finally { 156 Binder.restoreCallingIdentity(token); 157 Log.endSession(); 158 } 159 } 160 161 @Override setRinging(String callId, Session.Info sessionInfo)162 public void setRinging(String callId, Session.Info sessionInfo) { 163 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_RINGING, mPackageAbbreviation); 164 long token = Binder.clearCallingIdentity(); 165 try { 166 synchronized (mLock) { 167 logIncoming("setRinging %s", callId); 168 Call call = mCallIdMapper.getCall(callId); 169 if (call != null) { 170 mCallsManager.markCallAsRinging(call); 171 } else { 172 // Log.w(this, "setRinging, unknown call id: %s", msg.obj); 173 } 174 } 175 } catch (Throwable t) { 176 Log.e(ConnectionServiceWrapper.this, t, ""); 177 throw t; 178 } finally { 179 Binder.restoreCallingIdentity(token); 180 Log.endSession(); 181 } 182 } 183 184 @Override resetConnectionTime(String callId, Session.Info sessionInfo)185 public void resetConnectionTime(String callId, Session.Info sessionInfo) { 186 Log.startSession(sessionInfo, "CSW.rCCT", mPackageAbbreviation); 187 long token = Binder.clearCallingIdentity(); 188 try { 189 synchronized (mLock) { 190 logIncoming("resetConnectionTime %s", callId); 191 Call call = mCallIdMapper.getCall(callId); 192 if (call != null) { 193 mCallsManager.resetConnectionTime(call); 194 } else { 195 // Log.w(this, "resetConnectionTime, unknown call id: %s", msg.obj); 196 } 197 } 198 } finally { 199 Binder.restoreCallingIdentity(token); 200 Log.endSession(); 201 } 202 } 203 204 @Override setVideoProvider(String callId, IVideoProvider videoProvider, Session.Info sessionInfo)205 public void setVideoProvider(String callId, IVideoProvider videoProvider, 206 Session.Info sessionInfo) { 207 Log.startSession(sessionInfo, "CSW.sVP", mPackageAbbreviation); 208 long token = Binder.clearCallingIdentity(); 209 try { 210 synchronized (mLock) { 211 logIncoming("setVideoProvider %s", callId); 212 Call call = mCallIdMapper.getCall(callId); 213 if (call != null) { 214 call.setVideoProvider(videoProvider); 215 } 216 } 217 } catch (Throwable t) { 218 Log.e(ConnectionServiceWrapper.this, t, ""); 219 throw t; 220 } finally { 221 Binder.restoreCallingIdentity(token); 222 Log.endSession(); 223 } 224 } 225 226 @Override setDialing(String callId, Session.Info sessionInfo)227 public void setDialing(String callId, Session.Info sessionInfo) { 228 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_DIALING, mPackageAbbreviation); 229 long token = Binder.clearCallingIdentity(); 230 try { 231 synchronized (mLock) { 232 logIncoming("setDialing %s", callId); 233 Call call = mCallIdMapper.getCall(callId); 234 if (call != null) { 235 mCallsManager.markCallAsDialing(call); 236 } else { 237 // Log.w(this, "setDialing, unknown call id: %s", msg.obj); 238 } 239 } 240 } catch (Throwable t) { 241 Log.e(ConnectionServiceWrapper.this, t, ""); 242 throw t; 243 } finally { 244 Binder.restoreCallingIdentity(token); 245 Log.endSession(); 246 } 247 } 248 249 @Override setPulling(String callId, Session.Info sessionInfo)250 public void setPulling(String callId, Session.Info sessionInfo) { 251 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_PULLING, mPackageAbbreviation); 252 long token = Binder.clearCallingIdentity(); 253 try { 254 synchronized (mLock) { 255 logIncoming("setPulling %s", callId); 256 Call call = mCallIdMapper.getCall(callId); 257 if (call != null) { 258 mCallsManager.markCallAsPulling(call); 259 } 260 } 261 } catch (Throwable t) { 262 Log.e(ConnectionServiceWrapper.this, t, ""); 263 throw t; 264 } finally { 265 Binder.restoreCallingIdentity(token); 266 Log.endSession(); 267 } 268 } 269 270 @Override setDisconnected(String callId, DisconnectCause disconnectCause, Session.Info sessionInfo)271 public void setDisconnected(String callId, DisconnectCause disconnectCause, 272 Session.Info sessionInfo) { 273 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_DISCONNECTED, 274 mPackageAbbreviation); 275 long token = Binder.clearCallingIdentity(); 276 try { 277 synchronized (mLock) { 278 logIncoming("setDisconnected %s %s", callId, disconnectCause); 279 Call call = mCallIdMapper.getCall(callId); 280 Log.d(this, "disconnect call %s %s", disconnectCause, call); 281 if (call != null) { 282 mCallsManager.markCallAsDisconnected(call, disconnectCause); 283 } else { 284 // Log.w(this, "setDisconnected, unknown call id: %s", args.arg1); 285 } 286 } 287 } catch (Throwable t) { 288 Log.e(ConnectionServiceWrapper.this, t, ""); 289 throw t; 290 } finally { 291 Binder.restoreCallingIdentity(token); 292 Log.endSession(); 293 } 294 } 295 296 @Override setOnHold(String callId, Session.Info sessionInfo)297 public void setOnHold(String callId, Session.Info sessionInfo) { 298 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_ON_HOLD, mPackageAbbreviation); 299 long token = Binder.clearCallingIdentity(); 300 try { 301 synchronized (mLock) { 302 logIncoming("setOnHold %s", callId); 303 Call call = mCallIdMapper.getCall(callId); 304 if (call != null) { 305 mCallsManager.markCallAsOnHold(call); 306 } else { 307 // Log.w(this, "setOnHold, unknown call id: %s", msg.obj); 308 } 309 } 310 } catch (Throwable t) { 311 Log.e(ConnectionServiceWrapper.this, t, ""); 312 throw t; 313 } finally { 314 Binder.restoreCallingIdentity(token); 315 Log.endSession(); 316 } 317 } 318 319 @Override setRingbackRequested(String callId, boolean ringback, Session.Info sessionInfo)320 public void setRingbackRequested(String callId, boolean ringback, 321 Session.Info sessionInfo) { 322 Log.startSession(sessionInfo, "CSW.SRR", mPackageAbbreviation); 323 long token = Binder.clearCallingIdentity(); 324 try { 325 synchronized (mLock) { 326 logIncoming("setRingbackRequested %s %b", callId, ringback); 327 Call call = mCallIdMapper.getCall(callId); 328 if (call != null) { 329 call.setRingbackRequested(ringback); 330 } else { 331 // Log.w(this, "setRingback, unknown call id: %s", args.arg1); 332 } 333 } 334 } catch (Throwable t) { 335 Log.e(ConnectionServiceWrapper.this, t, ""); 336 throw t; 337 } finally { 338 Binder.restoreCallingIdentity(token); 339 Log.endSession(); 340 } 341 } 342 343 @Override removeCall(String callId, Session.Info sessionInfo)344 public void removeCall(String callId, Session.Info sessionInfo) { 345 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_REMOVE_CALL, mPackageAbbreviation); 346 long token = Binder.clearCallingIdentity(); 347 try { 348 synchronized (mLock) { 349 logIncoming("removeCall %s", callId); 350 Call call = mCallIdMapper.getCall(callId); 351 if (call != null) { 352 if (call.isAlive()) { 353 mCallsManager.markCallAsDisconnected( 354 call, new DisconnectCause(DisconnectCause.REMOTE)); 355 } else { 356 mCallsManager.markCallAsRemoved(call); 357 } 358 } 359 } 360 } catch (Throwable t) { 361 Log.e(ConnectionServiceWrapper.this, t, ""); 362 throw t; 363 } finally { 364 Binder.restoreCallingIdentity(token); 365 Log.endSession(); 366 } 367 } 368 369 @Override setConnectionCapabilities(String callId, int connectionCapabilities, Session.Info sessionInfo)370 public void setConnectionCapabilities(String callId, int connectionCapabilities, 371 Session.Info sessionInfo) { 372 Log.startSession(sessionInfo, "CSW.sCC", mPackageAbbreviation); 373 long token = Binder.clearCallingIdentity(); 374 try { 375 synchronized (mLock) { 376 logIncoming("setConnectionCapabilities %s %d", callId, connectionCapabilities); 377 Call call = mCallIdMapper.getCall(callId); 378 if (call != null) { 379 call.setConnectionCapabilities(connectionCapabilities); 380 } else { 381 // Log.w(ConnectionServiceWrapper.this, 382 // "setConnectionCapabilities, unknown call id: %s", msg.obj); 383 } 384 } 385 } catch (Throwable t) { 386 Log.e(ConnectionServiceWrapper.this, t, ""); 387 throw t; 388 } finally { 389 Binder.restoreCallingIdentity(token); 390 Log.endSession(); 391 } 392 } 393 394 @Override setConnectionProperties(String callId, int connectionProperties, Session.Info sessionInfo)395 public void setConnectionProperties(String callId, int connectionProperties, 396 Session.Info sessionInfo) { 397 Log.startSession("CSW.sCP", mPackageAbbreviation); 398 long token = Binder.clearCallingIdentity(); 399 try { 400 synchronized (mLock) { 401 logIncoming("setConnectionProperties %s %d", callId, connectionProperties); 402 Call call = mCallIdMapper.getCall(callId); 403 if (call != null) { 404 call.setConnectionProperties(connectionProperties); 405 } 406 } 407 } catch (Throwable t) { 408 Log.e(ConnectionServiceWrapper.this, t, ""); 409 throw t; 410 } finally { 411 Binder.restoreCallingIdentity(token); 412 Log.endSession(); 413 } 414 } 415 416 @Override setIsConferenced(String callId, String conferenceCallId, Session.Info sessionInfo)417 public void setIsConferenced(String callId, String conferenceCallId, 418 Session.Info sessionInfo) { 419 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_IS_CONFERENCED, 420 mPackageAbbreviation); 421 long token = Binder.clearCallingIdentity(); 422 try { 423 synchronized (mLock) { 424 logIncoming("setIsConferenced %s %s", callId, conferenceCallId); 425 Call childCall = mCallIdMapper.getCall(callId); 426 if (childCall != null) { 427 if (conferenceCallId == null) { 428 Log.d(this, "unsetting parent: %s", conferenceCallId); 429 childCall.setParentAndChildCall(null); 430 } else { 431 Call conferenceCall = mCallIdMapper.getCall(conferenceCallId); 432 childCall.setParentAndChildCall(conferenceCall); 433 } 434 } else { 435 // Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1); 436 } 437 } 438 } catch (Throwable t) { 439 Log.e(ConnectionServiceWrapper.this, t, ""); 440 throw t; 441 } finally { 442 Binder.restoreCallingIdentity(token); 443 Log.endSession(); 444 } 445 } 446 447 @Override setConferenceMergeFailed(String callId, Session.Info sessionInfo)448 public void setConferenceMergeFailed(String callId, Session.Info sessionInfo) { 449 Log.startSession(sessionInfo, "CSW.sCMF", mPackageAbbreviation); 450 long token = Binder.clearCallingIdentity(); 451 try { 452 synchronized (mLock) { 453 logIncoming("setConferenceMergeFailed %s", callId); 454 // TODO: we should move the UI for indication a merge failure here 455 // from CallNotifier.onSuppServiceFailed(). This way the InCallUI can 456 // deliver the message anyway that they want. b/20530631. 457 Call call = mCallIdMapper.getCall(callId); 458 if (call != null) { 459 call.onConnectionEvent(Connection.EVENT_CALL_MERGE_FAILED, null); 460 } else { 461 Log.w(this, "setConferenceMergeFailed, unknown call id: %s", callId); 462 } 463 } 464 } catch (Throwable t) { 465 Log.e(ConnectionServiceWrapper.this, t, ""); 466 throw t; 467 } finally { 468 Binder.restoreCallingIdentity(token); 469 Log.endSession(); 470 } 471 } 472 473 @Override addConferenceCall(String callId, ParcelableConference parcelableConference, Session.Info sessionInfo)474 public void addConferenceCall(String callId, ParcelableConference parcelableConference, 475 Session.Info sessionInfo) { 476 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_ADD_CONFERENCE_CALL, 477 mPackageAbbreviation); 478 479 if (parcelableConference.getConnectElapsedTimeMillis() != 0 480 && mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE) 481 != PackageManager.PERMISSION_GRANTED) { 482 Log.w(this, "addConferenceCall from caller without permission!"); 483 parcelableConference = new ParcelableConference.Builder( 484 parcelableConference.getPhoneAccount(), 485 parcelableConference.getState()) 486 .setConnectionCapabilities(parcelableConference.getConnectionCapabilities()) 487 .setConnectionProperties(parcelableConference.getConnectionProperties()) 488 .setConnectionIds(parcelableConference.getConnectionIds()) 489 .setVideoAttributes(parcelableConference.getVideoProvider(), 490 parcelableConference.getVideoState()) 491 .setStatusHints(parcelableConference.getStatusHints()) 492 .setExtras(parcelableConference.getExtras()) 493 .setAddress(parcelableConference.getHandle(), 494 parcelableConference.getHandlePresentation()) 495 // no caller display name set. 496 .setDisconnectCause(parcelableConference.getDisconnectCause()) 497 .setRingbackRequested(parcelableConference.isRingbackRequested()) 498 .build(); 499 } 500 501 long token = Binder.clearCallingIdentity(); 502 try { 503 synchronized (mLock) { 504 if (mCallIdMapper.getCall(callId) != null) { 505 Log.w(this, "Attempting to add a conference call using an existing " + 506 "call id %s", callId); 507 return; 508 } 509 logIncoming("addConferenceCall %s %s [%s]", callId, parcelableConference, 510 parcelableConference.getConnectionIds()); 511 512 // Make sure that there's at least one valid call. For remote connections 513 // we'll get a add conference msg from both the remote connection service 514 // and from the real connection service. 515 boolean hasValidCalls = false; 516 for (String connId : parcelableConference.getConnectionIds()) { 517 if (mCallIdMapper.getCall(connId) != null) { 518 hasValidCalls = true; 519 } 520 } 521 // But don't bail out if the connection count is 0, because that is a valid 522 // IMS conference state. 523 if (!hasValidCalls && parcelableConference.getConnectionIds().size() > 0) { 524 Log.d(this, "Attempting to add a conference with no valid calls"); 525 return; 526 } 527 528 PhoneAccountHandle phAcc = null; 529 if (parcelableConference != null && 530 parcelableConference.getPhoneAccount() != null) { 531 phAcc = parcelableConference.getPhoneAccount(); 532 } 533 534 Bundle connectionExtras = parcelableConference.getExtras(); 535 536 String connectIdToCheck = null; 537 if (connectionExtras != null && connectionExtras 538 .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) { 539 // Conference was added via a connection manager, see if its original id is 540 // known. 541 connectIdToCheck = connectionExtras 542 .getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID); 543 } else { 544 connectIdToCheck = callId; 545 } 546 547 Call conferenceCall; 548 // Check to see if this conference has already been added. 549 Call alreadyAddedConnection = mCallsManager 550 .getAlreadyAddedConnection(connectIdToCheck); 551 if (alreadyAddedConnection != null && mCallIdMapper.getCall(callId) == null) { 552 // We are currently attempting to add the conference via a connection mgr, 553 // and the originating ConnectionService has already added it. Instead of 554 // making a new Telecom call, we will simply add it to the ID mapper here, 555 // and replace the ConnectionService on the call. 556 mCallIdMapper.addCall(alreadyAddedConnection, callId); 557 alreadyAddedConnection.replaceConnectionService( 558 ConnectionServiceWrapper.this); 559 conferenceCall = alreadyAddedConnection; 560 } else { 561 // need to create a new Call 562 Call newConferenceCall = mCallsManager.createConferenceCall(callId, 563 phAcc, parcelableConference); 564 mCallIdMapper.addCall(newConferenceCall, callId); 565 newConferenceCall.setConnectionService(ConnectionServiceWrapper.this); 566 conferenceCall = newConferenceCall; 567 } 568 569 Log.d(this, "adding children to conference %s phAcc %s", 570 parcelableConference.getConnectionIds(), phAcc); 571 for (String connId : parcelableConference.getConnectionIds()) { 572 Call childCall = mCallIdMapper.getCall(connId); 573 Log.d(this, "found child: %s", connId); 574 if (childCall != null) { 575 childCall.setParentAndChildCall(conferenceCall); 576 } 577 } 578 } 579 } catch (Throwable t) { 580 Log.e(ConnectionServiceWrapper.this, t, ""); 581 throw t; 582 } finally { 583 Binder.restoreCallingIdentity(token); 584 Log.endSession(); 585 } 586 } 587 588 @Override onPostDialWait(String callId, String remaining, Session.Info sessionInfo)589 public void onPostDialWait(String callId, String remaining, 590 Session.Info sessionInfo) throws RemoteException { 591 Log.startSession(sessionInfo, "CSW.oPDW", mPackageAbbreviation); 592 long token = Binder.clearCallingIdentity(); 593 try { 594 synchronized (mLock) { 595 logIncoming("onPostDialWait %s %s", callId, remaining); 596 Call call = mCallIdMapper.getCall(callId); 597 if (call != null) { 598 call.onPostDialWait(remaining); 599 } else { 600 // Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1); 601 } 602 } 603 } catch (Throwable t) { 604 Log.e(ConnectionServiceWrapper.this, t, ""); 605 throw t; 606 } finally { 607 Binder.restoreCallingIdentity(token); 608 Log.endSession(); 609 } 610 } 611 612 @Override onPostDialChar(String callId, char nextChar, Session.Info sessionInfo)613 public void onPostDialChar(String callId, char nextChar, 614 Session.Info sessionInfo) throws RemoteException { 615 Log.startSession(sessionInfo, "CSW.oPDC", mPackageAbbreviation); 616 long token = Binder.clearCallingIdentity(); 617 try { 618 synchronized (mLock) { 619 logIncoming("onPostDialChar %s %s", callId, nextChar); 620 Call call = mCallIdMapper.getCall(callId); 621 if (call != null) { 622 call.onPostDialChar(nextChar); 623 } else { 624 // Log.w(this, "onPostDialChar, unknown call id: %s", args.arg1); 625 } 626 } 627 } catch (Throwable t) { 628 Log.e(ConnectionServiceWrapper.this, t, ""); 629 throw t; 630 } finally { 631 Binder.restoreCallingIdentity(token); 632 Log.endSession(); 633 } 634 } 635 636 @Override queryRemoteConnectionServices(RemoteServiceCallback callback, String callingPackage, Session.Info sessionInfo)637 public void queryRemoteConnectionServices(RemoteServiceCallback callback, 638 String callingPackage, Session.Info sessionInfo) { 639 final UserHandle callingUserHandle = Binder.getCallingUserHandle(); 640 Log.startSession(sessionInfo, "CSW.qRCS", mPackageAbbreviation); 641 long token = Binder.clearCallingIdentity(); 642 try { 643 synchronized (mLock) { 644 logIncoming("queryRemoteConnectionServices callingPackage=" + callingPackage); 645 ConnectionServiceWrapper.this 646 .queryRemoteConnectionServices(callingUserHandle, callingPackage, 647 callback); 648 } 649 } catch (Throwable t) { 650 Log.e(ConnectionServiceWrapper.this, t, ""); 651 throw t; 652 } finally { 653 Binder.restoreCallingIdentity(token); 654 Log.endSession(); 655 } 656 } 657 658 @Override setVideoState(String callId, int videoState, Session.Info sessionInfo)659 public void setVideoState(String callId, int videoState, Session.Info sessionInfo) { 660 Log.startSession(sessionInfo, "CSW.sVS", mPackageAbbreviation); 661 long token = Binder.clearCallingIdentity(); 662 try { 663 synchronized (mLock) { 664 logIncoming("setVideoState %s %d", callId, videoState); 665 Call call = mCallIdMapper.getCall(callId); 666 if (call != null) { 667 call.setVideoState(videoState); 668 } 669 } 670 } catch (Throwable t) { 671 Log.e(ConnectionServiceWrapper.this, t, ""); 672 throw t; 673 } finally { 674 Binder.restoreCallingIdentity(token); 675 Log.endSession(); 676 } 677 } 678 679 @Override setIsVoipAudioMode(String callId, boolean isVoip, Session.Info sessionInfo)680 public void setIsVoipAudioMode(String callId, boolean isVoip, Session.Info sessionInfo) { 681 Log.startSession(sessionInfo, "CSW.sIVAM", mPackageAbbreviation); 682 long token = Binder.clearCallingIdentity(); 683 try { 684 synchronized (mLock) { 685 logIncoming("setIsVoipAudioMode %s %b", callId, isVoip); 686 Call call = mCallIdMapper.getCall(callId); 687 if (call != null) { 688 call.setIsVoipAudioMode(isVoip); 689 } 690 } 691 } catch (Throwable t) { 692 Log.e(ConnectionServiceWrapper.this, t, ""); 693 throw t; 694 } finally { 695 Binder.restoreCallingIdentity(token); 696 Log.endSession(); 697 } 698 } 699 700 @Override setAudioRoute(String callId, int audioRoute, String bluetoothAddress, Session.Info sessionInfo)701 public void setAudioRoute(String callId, int audioRoute, 702 String bluetoothAddress, Session.Info sessionInfo) { 703 Log.startSession(sessionInfo, "CSW.sAR", mPackageAbbreviation); 704 long token = Binder.clearCallingIdentity(); 705 try { 706 synchronized (mLock) { 707 logIncoming("setAudioRoute %s %s", callId, 708 CallAudioState.audioRouteToString(audioRoute)); 709 mCallsManager.setAudioRoute(audioRoute, bluetoothAddress); 710 } 711 } catch (Throwable t) { 712 Log.e(ConnectionServiceWrapper.this, t, ""); 713 throw t; 714 } finally { 715 Binder.restoreCallingIdentity(token); 716 Log.endSession(); 717 } 718 } 719 720 @Override setStatusHints(String callId, StatusHints statusHints, Session.Info sessionInfo)721 public void setStatusHints(String callId, StatusHints statusHints, 722 Session.Info sessionInfo) { 723 Log.startSession(sessionInfo, "CSW.sSH", mPackageAbbreviation); 724 long token = Binder.clearCallingIdentity(); 725 try { 726 synchronized (mLock) { 727 logIncoming("setStatusHints %s %s", callId, statusHints); 728 Call call = mCallIdMapper.getCall(callId); 729 if (call != null) { 730 call.setStatusHints(statusHints); 731 } 732 } 733 } catch (Throwable t) { 734 Log.e(ConnectionServiceWrapper.this, t, ""); 735 throw t; 736 } finally { 737 Binder.restoreCallingIdentity(token); 738 Log.endSession(); 739 } 740 } 741 742 @Override putExtras(String callId, Bundle extras, Session.Info sessionInfo)743 public void putExtras(String callId, Bundle extras, Session.Info sessionInfo) { 744 Log.startSession(sessionInfo, "CSW.pE", mPackageAbbreviation); 745 long token = Binder.clearCallingIdentity(); 746 try { 747 synchronized (mLock) { 748 Bundle.setDefusable(extras, true); 749 Call call = mCallIdMapper.getCall(callId); 750 if (call != null) { 751 call.putExtras(Call.SOURCE_CONNECTION_SERVICE, extras); 752 } 753 } 754 } catch (Throwable t) { 755 Log.e(ConnectionServiceWrapper.this, t, ""); 756 throw t; 757 } finally { 758 Binder.restoreCallingIdentity(token); 759 Log.endSession(); 760 } 761 } 762 763 @Override removeExtras(String callId, List<String> keys, Session.Info sessionInfo)764 public void removeExtras(String callId, List<String> keys, Session.Info sessionInfo) { 765 Log.startSession(sessionInfo, "CSW.rE", mPackageAbbreviation); 766 long token = Binder.clearCallingIdentity(); 767 try { 768 synchronized (mLock) { 769 logIncoming("removeExtra %s %s", callId, keys); 770 Call call = mCallIdMapper.getCall(callId); 771 if (call != null) { 772 call.removeExtras(Call.SOURCE_CONNECTION_SERVICE, keys); 773 } 774 } 775 } catch (Throwable t) { 776 Log.e(ConnectionServiceWrapper.this, t, ""); 777 throw t; 778 } finally { 779 Binder.restoreCallingIdentity(token); 780 Log.endSession(); 781 } 782 } 783 784 @Override setAddress(String callId, Uri address, int presentation, Session.Info sessionInfo)785 public void setAddress(String callId, Uri address, int presentation, 786 Session.Info sessionInfo) { 787 Log.startSession(sessionInfo, "CSW.sA", mPackageAbbreviation); 788 789 long token = Binder.clearCallingIdentity(); 790 try { 791 synchronized (mLock) { 792 logIncoming("setAddress %s %s %d", callId, address, presentation); 793 Call call = mCallIdMapper.getCall(callId); 794 if (call != null) { 795 call.setHandle(address, presentation); 796 } 797 } 798 } catch (Throwable t) { 799 Log.e(ConnectionServiceWrapper.this, t, ""); 800 throw t; 801 } finally { 802 Binder.restoreCallingIdentity(token); 803 Log.endSession(); 804 } 805 } 806 807 @Override setCallerDisplayName(String callId, String callerDisplayName, int presentation, Session.Info sessionInfo)808 public void setCallerDisplayName(String callId, String callerDisplayName, int presentation, 809 Session.Info sessionInfo) { 810 Log.startSession(sessionInfo, "CSW.sCDN", mPackageAbbreviation); 811 long token = Binder.clearCallingIdentity(); 812 try { 813 synchronized (mLock) { 814 logIncoming("setCallerDisplayName %s %s %d", callId, callerDisplayName, 815 presentation); 816 Call call = mCallIdMapper.getCall(callId); 817 if (call != null) { 818 call.setCallerDisplayName(callerDisplayName, presentation); 819 } 820 } 821 } catch (Throwable t) { 822 Log.e(ConnectionServiceWrapper.this, t, ""); 823 throw t; 824 } finally { 825 Binder.restoreCallingIdentity(token); 826 Log.endSession(); 827 } 828 } 829 830 @Override setConferenceableConnections(String callId, List<String> conferenceableCallIds, Session.Info sessionInfo)831 public void setConferenceableConnections(String callId, List<String> conferenceableCallIds, 832 Session.Info sessionInfo) { 833 Log.startSession(sessionInfo, "CSW.sCC", mPackageAbbreviation); 834 long token = Binder.clearCallingIdentity(); 835 try { 836 synchronized (mLock) { 837 838 Call call = mCallIdMapper.getCall(callId); 839 if (call != null) { 840 logIncoming("setConferenceableConnections %s %s", callId, 841 conferenceableCallIds); 842 List<Call> conferenceableCalls = 843 new ArrayList<>(conferenceableCallIds.size()); 844 for (String otherId : conferenceableCallIds) { 845 Call otherCall = mCallIdMapper.getCall(otherId); 846 if (otherCall != null && otherCall != call) { 847 conferenceableCalls.add(otherCall); 848 } 849 } 850 call.setConferenceableCalls(conferenceableCalls); 851 } 852 } 853 } catch (Throwable t) { 854 Log.e(ConnectionServiceWrapper.this, t, ""); 855 throw t; 856 } finally { 857 Binder.restoreCallingIdentity(token); 858 Log.endSession(); 859 } 860 } 861 862 @Override addExistingConnection(String callId, ParcelableConnection connection, Session.Info sessionInfo)863 public void addExistingConnection(String callId, ParcelableConnection connection, 864 Session.Info sessionInfo) { 865 Log.startSession(sessionInfo, "CSW.aEC", mPackageAbbreviation); 866 UserHandle userHandle = Binder.getCallingUserHandle(); 867 // Check that the Calling Package matches PhoneAccountHandle's Component Package 868 PhoneAccountHandle callingPhoneAccountHandle = connection.getPhoneAccount(); 869 if (callingPhoneAccountHandle != null) { 870 mAppOpsManager.checkPackage(Binder.getCallingUid(), 871 callingPhoneAccountHandle.getComponentName().getPackageName()); 872 } 873 874 long token = Binder.clearCallingIdentity(); 875 try { 876 synchronized (mLock) { 877 // Make sure that the PhoneAccount associated with the incoming 878 // ParcelableConnection is in fact registered to Telecom and is being called 879 // from the correct user. 880 List<PhoneAccountHandle> accountHandles = 881 // Include CAPABILITY_EMERGENCY_CALLS_ONLY in this list in case we are adding 882 // an emergency call. 883 mPhoneAccountRegistrar.getCallCapablePhoneAccounts(null /*uriScheme*/, 884 false /*includeDisabledAccounts*/, userHandle, 0 /*capabilities*/, 885 0 /*excludedCapabilities*/); 886 PhoneAccountHandle phoneAccountHandle = null; 887 for (PhoneAccountHandle accountHandle : accountHandles) { 888 if(accountHandle.equals(callingPhoneAccountHandle)) { 889 phoneAccountHandle = accountHandle; 890 } 891 } 892 // Allow the Sim call manager account as well, even if its disabled. 893 if (phoneAccountHandle == null && callingPhoneAccountHandle != null) { 894 // Search all SIM PhoneAccounts to see if there is a SIM call manager 895 // associated with any of them and verify that the calling handle matches. 896 for (PhoneAccountHandle handle : 897 mPhoneAccountRegistrar.getSimPhoneAccounts(userHandle)) { 898 int subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount( 899 handle); 900 PhoneAccountHandle connectionMgrHandle = 901 mPhoneAccountRegistrar.getSimCallManager(subId, userHandle); 902 if (callingPhoneAccountHandle.equals(connectionMgrHandle)) { 903 phoneAccountHandle = connectionMgrHandle; 904 break; 905 } 906 } 907 } 908 if (phoneAccountHandle != null) { 909 logIncoming("addExistingConnection %s %s", callId, connection); 910 911 Bundle connectionExtras = connection.getExtras(); 912 String connectIdToCheck = null; 913 if (connectionExtras != null && connectionExtras 914 .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) { 915 connectIdToCheck = connectionExtras 916 .getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID); 917 } else { 918 connectIdToCheck = callId; 919 } 920 // Check to see if this Connection has already been added. 921 Call alreadyAddedConnection = mCallsManager 922 .getAlreadyAddedConnection(connectIdToCheck); 923 924 if (alreadyAddedConnection != null 925 && mCallIdMapper.getCall(callId) == null) { 926 mCallIdMapper.addCall(alreadyAddedConnection, callId); 927 alreadyAddedConnection 928 .replaceConnectionService(ConnectionServiceWrapper.this); 929 return; 930 } 931 932 Call existingCall = mCallsManager 933 .createCallForExistingConnection(callId, connection); 934 mCallIdMapper.addCall(existingCall, callId); 935 existingCall.setConnectionService(ConnectionServiceWrapper.this); 936 } else { 937 Log.e(this, new RemoteException("The PhoneAccount being used is not " + 938 "currently registered with Telecom."), "Unable to " + 939 "addExistingConnection."); 940 } 941 } 942 } catch (Throwable t) { 943 Log.e(ConnectionServiceWrapper.this, t, ""); 944 throw t; 945 } finally { 946 Binder.restoreCallingIdentity(token); 947 Log.endSession(); 948 } 949 } 950 951 @Override onConnectionEvent(String callId, String event, Bundle extras, Session.Info sessionInfo)952 public void onConnectionEvent(String callId, String event, Bundle extras, 953 Session.Info sessionInfo) { 954 Log.startSession(sessionInfo, "CSW.oCE", mPackageAbbreviation); 955 long token = Binder.clearCallingIdentity(); 956 try { 957 synchronized (mLock) { 958 Bundle.setDefusable(extras, true); 959 Call call = mCallIdMapper.getCall(callId); 960 if (call != null) { 961 call.onConnectionEvent(event, extras); 962 } 963 } 964 } catch (Throwable t) { 965 Log.e(ConnectionServiceWrapper.this, t, ""); 966 throw t; 967 } finally { 968 Binder.restoreCallingIdentity(token); 969 Log.endSession(); 970 } 971 } 972 973 @Override onRttInitiationSuccess(String callId, Session.Info sessionInfo)974 public void onRttInitiationSuccess(String callId, Session.Info sessionInfo) 975 throws RemoteException { 976 977 } 978 979 @Override onRttInitiationFailure(String callId, int reason, Session.Info sessionInfo)980 public void onRttInitiationFailure(String callId, int reason, Session.Info sessionInfo) 981 throws RemoteException { 982 Log.startSession(sessionInfo, "CSW.oRIF", mPackageAbbreviation); 983 long token = Binder.clearCallingIdentity(); 984 try { 985 synchronized (mLock) { 986 Call call = mCallIdMapper.getCall(callId); 987 if (call != null) { 988 call.onRttConnectionFailure(reason); 989 } 990 } 991 } catch (Throwable t) { 992 Log.e(ConnectionServiceWrapper.this, t, ""); 993 throw t; 994 } finally { 995 Binder.restoreCallingIdentity(token); 996 Log.endSession(); 997 } 998 } 999 1000 @Override onRttSessionRemotelyTerminated(String callId, Session.Info sessionInfo)1001 public void onRttSessionRemotelyTerminated(String callId, Session.Info sessionInfo) 1002 throws RemoteException { 1003 1004 } 1005 1006 @Override onRemoteRttRequest(String callId, Session.Info sessionInfo)1007 public void onRemoteRttRequest(String callId, Session.Info sessionInfo) 1008 throws RemoteException { 1009 Log.startSession(sessionInfo, "CSW.oRRR", mPackageAbbreviation); 1010 long token = Binder.clearCallingIdentity(); 1011 try { 1012 synchronized (mLock) { 1013 Call call = mCallIdMapper.getCall(callId); 1014 if (call != null) { 1015 call.onRemoteRttRequest(); 1016 } 1017 } 1018 } catch (Throwable t) { 1019 Log.e(ConnectionServiceWrapper.this, t, ""); 1020 throw t; 1021 } finally { 1022 Binder.restoreCallingIdentity(token); 1023 Log.endSession(); 1024 } 1025 } 1026 1027 @Override onPhoneAccountChanged(String callId, PhoneAccountHandle pHandle, Session.Info sessionInfo)1028 public void onPhoneAccountChanged(String callId, PhoneAccountHandle pHandle, 1029 Session.Info sessionInfo) throws RemoteException { 1030 // Check that the Calling Package matches PhoneAccountHandle's Component Package 1031 if (pHandle != null) { 1032 mAppOpsManager.checkPackage(Binder.getCallingUid(), 1033 pHandle.getComponentName().getPackageName()); 1034 } 1035 Log.startSession(sessionInfo, "CSW.oPAC", mPackageAbbreviation); 1036 long token = Binder.clearCallingIdentity(); 1037 try { 1038 synchronized (mLock) { 1039 Call call = mCallIdMapper.getCall(callId); 1040 if (call != null) { 1041 call.setTargetPhoneAccount(pHandle); 1042 } 1043 } 1044 } catch (Throwable t) { 1045 Log.e(ConnectionServiceWrapper.this, t, ""); 1046 throw t; 1047 } finally { 1048 Binder.restoreCallingIdentity(token); 1049 Log.endSession(); 1050 } 1051 } 1052 1053 @Override onConnectionServiceFocusReleased(Session.Info sessionInfo)1054 public void onConnectionServiceFocusReleased(Session.Info sessionInfo) 1055 throws RemoteException { 1056 Log.startSession(sessionInfo, "CSW.oCSFR", mPackageAbbreviation); 1057 long token = Binder.clearCallingIdentity(); 1058 try { 1059 synchronized (mLock) { 1060 mConnSvrFocusListener.onConnectionServiceReleased( 1061 ConnectionServiceWrapper.this); 1062 } 1063 } catch (Throwable t) { 1064 Log.e(ConnectionServiceWrapper.this, t, ""); 1065 throw t; 1066 } finally { 1067 Binder.restoreCallingIdentity(token); 1068 Log.endSession(); 1069 } 1070 } 1071 1072 @Override setConferenceState(String callId, boolean isConference, Session.Info sessionInfo)1073 public void setConferenceState(String callId, boolean isConference, 1074 Session.Info sessionInfo) throws RemoteException { 1075 Log.startSession(sessionInfo, "CSW.sCS", mPackageAbbreviation); 1076 1077 if (mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE) 1078 != PackageManager.PERMISSION_GRANTED) { 1079 Log.w(this, "setConferenceState from caller without permission."); 1080 Log.endSession(); 1081 return; 1082 } 1083 1084 long token = Binder.clearCallingIdentity(); 1085 try { 1086 synchronized (mLock) { 1087 Call call = mCallIdMapper.getCall(callId); 1088 if (call != null) { 1089 call.setConferenceState(isConference); 1090 } 1091 } 1092 } catch (Throwable t) { 1093 Log.e(ConnectionServiceWrapper.this, t, ""); 1094 throw t; 1095 } finally { 1096 Binder.restoreCallingIdentity(token); 1097 Log.endSession(); 1098 } 1099 } 1100 1101 @Override setCallDirection(String callId, int direction, Session.Info sessionInfo)1102 public void setCallDirection(String callId, int direction, Session.Info sessionInfo) { 1103 Log.startSession(sessionInfo, "CSW.sCD", mPackageAbbreviation); 1104 1105 if (mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE) 1106 != PackageManager.PERMISSION_GRANTED) { 1107 Log.w(this, "setCallDirection from caller without permission."); 1108 Log.endSession(); 1109 return; 1110 } 1111 1112 long token = Binder.clearCallingIdentity(); 1113 try { 1114 synchronized (mLock) { 1115 logIncoming("setCallDirection %s %d", callId, direction); 1116 Call call = mCallIdMapper.getCall(callId); 1117 if (call != null) { 1118 call.setCallDirection(Call.getRemappedCallDirection(direction)); 1119 } 1120 } 1121 } catch (Throwable t) { 1122 Log.e(ConnectionServiceWrapper.this, t, ""); 1123 throw t; 1124 } finally { 1125 Binder.restoreCallingIdentity(token); 1126 Log.endSession(); 1127 } 1128 } 1129 } 1130 1131 private final Adapter mAdapter = new Adapter(); 1132 private final CallIdMapper mCallIdMapper = new CallIdMapper(Call::getConnectionId); 1133 private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>(); 1134 1135 private Binder2 mBinder = new Binder2(); 1136 private IConnectionService mServiceInterface; 1137 private final ConnectionServiceRepository mConnectionServiceRepository; 1138 private final PhoneAccountRegistrar mPhoneAccountRegistrar; 1139 private final CallsManager mCallsManager; 1140 private final AppOpsManager mAppOpsManager; 1141 private final Context mContext; 1142 1143 private ConnectionServiceFocusManager.ConnectionServiceFocusListener mConnSvrFocusListener; 1144 1145 /** 1146 * Creates a connection service. 1147 * 1148 * @param componentName The component name of the service with which to bind. 1149 * @param connectionServiceRepository Connection service repository. 1150 * @param phoneAccountRegistrar Phone account registrar 1151 * @param callsManager Calls manager 1152 * @param context The context. 1153 * @param userHandle The {@link UserHandle} to use when binding. 1154 */ ConnectionServiceWrapper( ComponentName componentName, ConnectionServiceRepository connectionServiceRepository, PhoneAccountRegistrar phoneAccountRegistrar, CallsManager callsManager, Context context, TelecomSystem.SyncRoot lock, UserHandle userHandle)1155 ConnectionServiceWrapper( 1156 ComponentName componentName, 1157 ConnectionServiceRepository connectionServiceRepository, 1158 PhoneAccountRegistrar phoneAccountRegistrar, 1159 CallsManager callsManager, 1160 Context context, 1161 TelecomSystem.SyncRoot lock, 1162 UserHandle userHandle) { 1163 super(ConnectionService.SERVICE_INTERFACE, componentName, context, lock, userHandle); 1164 mConnectionServiceRepository = connectionServiceRepository; 1165 phoneAccountRegistrar.addListener(new PhoneAccountRegistrar.Listener() { 1166 // TODO -- Upon changes to PhoneAccountRegistrar, need to re-wire connections 1167 // To do this, we must proxy remote ConnectionService objects 1168 }); 1169 mPhoneAccountRegistrar = phoneAccountRegistrar; 1170 mCallsManager = callsManager; 1171 mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 1172 mContext = context; 1173 } 1174 1175 /** See {@link IConnectionService#addConnectionServiceAdapter}. */ addConnectionServiceAdapter(IConnectionServiceAdapter adapter)1176 private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) { 1177 if (isServiceValid("addConnectionServiceAdapter")) { 1178 try { 1179 logOutgoing("addConnectionServiceAdapter %s", adapter); 1180 mServiceInterface.addConnectionServiceAdapter(adapter, Log.getExternalSession()); 1181 } catch (RemoteException e) { 1182 } 1183 } 1184 } 1185 1186 /** See {@link IConnectionService#removeConnectionServiceAdapter}. */ removeConnectionServiceAdapter(IConnectionServiceAdapter adapter)1187 private void removeConnectionServiceAdapter(IConnectionServiceAdapter adapter) { 1188 if (isServiceValid("removeConnectionServiceAdapter")) { 1189 try { 1190 logOutgoing("removeConnectionServiceAdapter %s", adapter); 1191 mServiceInterface.removeConnectionServiceAdapter(adapter, Log.getExternalSession()); 1192 } catch (RemoteException e) { 1193 } 1194 } 1195 } 1196 1197 /** 1198 * Creates a conference for a new outgoing call or attach to an existing incoming call. 1199 */ createConference(final Call call, final CreateConnectionResponse response)1200 public void createConference(final Call call, final CreateConnectionResponse response) { 1201 Log.d(this, "createConference(%s) via %s.", call, getComponentName()); 1202 BindCallback callback = new BindCallback() { 1203 @Override 1204 public void onSuccess() { 1205 String callId = mCallIdMapper.getCallId(call); 1206 mPendingResponses.put(callId, response); 1207 1208 Bundle extras = call.getIntentExtras(); 1209 1210 Log.addEvent(call, LogUtils.Events.START_CONFERENCE, 1211 Log.piiHandle(call.getHandle())); 1212 1213 ConnectionRequest connectionRequest = new ConnectionRequest.Builder() 1214 .setAccountHandle(call.getTargetPhoneAccount()) 1215 .setAddress(call.getHandle()) 1216 .setExtras(extras) 1217 .setVideoState(call.getVideoState()) 1218 .setTelecomCallId(callId) 1219 // For self-managed incoming calls, if there is another ongoing call Telecom 1220 // is responsible for showing a UI to ask the user if they'd like to answer 1221 // this new incoming call. 1222 .setShouldShowIncomingCallUi( 1223 !mCallsManager.shouldShowSystemIncomingCallUi(call)) 1224 .setRttPipeFromInCall(call.getInCallToCsRttPipeForCs()) 1225 .setRttPipeToInCall(call.getCsToInCallRttPipeForCs()) 1226 .setParticipants(call.getParticipants()) 1227 .setIsAdhocConferenceCall(call.isAdhocConferenceCall()) 1228 .build(); 1229 1230 try { 1231 mServiceInterface.createConference( 1232 call.getConnectionManagerPhoneAccount(), 1233 callId, 1234 connectionRequest, 1235 call.shouldAttachToExistingConnection(), 1236 call.isUnknown(), 1237 Log.getExternalSession(TELECOM_ABBREVIATION)); 1238 1239 } catch (RemoteException e) { 1240 Log.e(this, e, "Failure to createConference -- %s", getComponentName()); 1241 mPendingResponses.remove(callId).handleCreateConferenceFailure( 1242 new DisconnectCause(DisconnectCause.ERROR, e.toString())); 1243 } 1244 } 1245 1246 @Override 1247 public void onFailure() { 1248 Log.e(this, new Exception(), "Failure to conference %s", getComponentName()); 1249 response.handleCreateConferenceFailure(new DisconnectCause(DisconnectCause.ERROR)); 1250 } 1251 }; 1252 1253 mBinder.bind(callback, call); 1254 1255 } 1256 1257 /** 1258 * Creates a new connection for a new outgoing call or to attach to an existing incoming call. 1259 */ 1260 @VisibleForTesting createConnection(final Call call, final CreateConnectionResponse response)1261 public void createConnection(final Call call, final CreateConnectionResponse response) { 1262 Log.i(this, "createConnection(%s) via %s.", call, getComponentName()); 1263 BindCallback callback = new BindCallback() { 1264 @Override 1265 public void onSuccess() { 1266 String callId = mCallIdMapper.getCallId(call); 1267 mPendingResponses.put(callId, response); 1268 1269 GatewayInfo gatewayInfo = call.getGatewayInfo(); 1270 Bundle extras = call.getIntentExtras(); 1271 if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null && 1272 gatewayInfo.getOriginalAddress() != null) { 1273 extras = (Bundle) extras.clone(); 1274 extras.putString( 1275 TelecomManager.GATEWAY_PROVIDER_PACKAGE, 1276 gatewayInfo.getGatewayProviderPackageName()); 1277 extras.putParcelable( 1278 TelecomManager.GATEWAY_ORIGINAL_ADDRESS, 1279 gatewayInfo.getOriginalAddress()); 1280 } 1281 1282 if (call.isIncoming() && mCallsManager.getEmergencyCallHelper() 1283 .getLastEmergencyCallTimeMillis() > 0) { 1284 // Add the last emergency call time to the connection request for incoming calls 1285 if (extras == call.getIntentExtras()) { 1286 extras = (Bundle) extras.clone(); 1287 } 1288 extras.putLong(android.telecom.Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 1289 mCallsManager.getEmergencyCallHelper().getLastEmergencyCallTimeMillis()); 1290 } 1291 1292 // Call is incoming and added because we're handing over from another; tell CS 1293 // that its expected to handover. 1294 if (call.isIncoming() && call.getHandoverSourceCall() != null) { 1295 extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER, true); 1296 extras.putParcelable(TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT, 1297 call.getHandoverSourceCall().getTargetPhoneAccount()); 1298 } 1299 1300 Log.addEvent(call, LogUtils.Events.START_CONNECTION, 1301 Log.piiHandle(call.getHandle()) + " via:" + 1302 getComponentName().getPackageName()); 1303 1304 ConnectionRequest connectionRequest = new ConnectionRequest.Builder() 1305 .setAccountHandle(call.getTargetPhoneAccount()) 1306 .setAddress(call.getHandle()) 1307 .setExtras(extras) 1308 .setVideoState(call.getVideoState()) 1309 .setTelecomCallId(callId) 1310 // For self-managed incoming calls, if there is another ongoing call Telecom 1311 // is responsible for showing a UI to ask the user if they'd like to answer 1312 // this new incoming call. 1313 .setShouldShowIncomingCallUi( 1314 !mCallsManager.shouldShowSystemIncomingCallUi(call)) 1315 .setRttPipeFromInCall(call.getInCallToCsRttPipeForCs()) 1316 .setRttPipeToInCall(call.getCsToInCallRttPipeForCs()) 1317 .build(); 1318 1319 try { 1320 mServiceInterface.createConnection( 1321 call.getConnectionManagerPhoneAccount(), 1322 callId, 1323 connectionRequest, 1324 call.shouldAttachToExistingConnection(), 1325 call.isUnknown(), 1326 Log.getExternalSession(TELECOM_ABBREVIATION)); 1327 1328 } catch (RemoteException e) { 1329 Log.e(this, e, "Failure to createConnection -- %s", getComponentName()); 1330 mPendingResponses.remove(callId).handleCreateConnectionFailure( 1331 new DisconnectCause(DisconnectCause.ERROR, e.toString())); 1332 } 1333 } 1334 1335 @Override 1336 public void onFailure() { 1337 Log.e(this, new Exception(), "Failure to call %s", getComponentName()); 1338 response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.ERROR)); 1339 } 1340 }; 1341 1342 mBinder.bind(callback, call); 1343 } 1344 1345 /** 1346 * Notifies the {@link ConnectionService} associated with a {@link Call} that the request to 1347 * create a connection has been denied or failed. 1348 * @param call The call. 1349 */ createConnectionFailed(final Call call)1350 void createConnectionFailed(final Call call) { 1351 Log.d(this, "createConnectionFailed(%s) via %s.", call, getComponentName()); 1352 BindCallback callback = new BindCallback() { 1353 @Override 1354 public void onSuccess() { 1355 final String callId = mCallIdMapper.getCallId(call); 1356 // If still bound, tell the connection service create connection has failed. 1357 if (callId != null && isServiceValid("createConnectionFailed")) { 1358 Log.addEvent(call, LogUtils.Events.CREATE_CONNECTION_FAILED, 1359 Log.piiHandle(call.getHandle())); 1360 try { 1361 logOutgoing("createConnectionFailed %s", callId); 1362 mServiceInterface.createConnectionFailed( 1363 call.getConnectionManagerPhoneAccount(), 1364 callId, 1365 new ConnectionRequest( 1366 call.getTargetPhoneAccount(), 1367 call.getHandle(), 1368 call.getIntentExtras(), 1369 call.getVideoState(), 1370 callId, 1371 false), 1372 call.isIncoming(), 1373 Log.getExternalSession(TELECOM_ABBREVIATION)); 1374 call.setDisconnectCause(new DisconnectCause(DisconnectCause.CANCELED)); 1375 call.disconnect(); 1376 } catch (RemoteException e) { 1377 } 1378 } 1379 } 1380 1381 @Override 1382 public void onFailure() { 1383 // Binding failed. Oh no. 1384 Log.w(this, "onFailure - could not bind to CS for call %s", call.getId()); 1385 } 1386 }; 1387 1388 mBinder.bind(callback, call); 1389 } 1390 1391 /** 1392 * Notifies the {@link ConnectionService} associated with a {@link Call} that the request to 1393 * create a conference has been denied or failed. 1394 * @param call The call. 1395 */ createConferenceFailed(final Call call)1396 void createConferenceFailed(final Call call) { 1397 Log.d(this, "createConferenceFailed(%s) via %s.", call, getComponentName()); 1398 BindCallback callback = new BindCallback() { 1399 @Override 1400 public void onSuccess() { 1401 final String callId = mCallIdMapper.getCallId(call); 1402 // If still bound, tell the connection service create connection has failed. 1403 if (callId != null && isServiceValid("createConferenceFailed")) { 1404 Log.addEvent(call, LogUtils.Events.CREATE_CONFERENCE_FAILED, 1405 Log.piiHandle(call.getHandle())); 1406 try { 1407 logOutgoing("createConferenceFailed %s", callId); 1408 mServiceInterface.createConferenceFailed( 1409 call.getConnectionManagerPhoneAccount(), 1410 callId, 1411 new ConnectionRequest( 1412 call.getTargetPhoneAccount(), 1413 call.getHandle(), 1414 call.getIntentExtras(), 1415 call.getVideoState(), 1416 callId, 1417 false), 1418 call.isIncoming(), 1419 Log.getExternalSession(TELECOM_ABBREVIATION)); 1420 call.setDisconnectCause(new DisconnectCause(DisconnectCause.CANCELED)); 1421 call.disconnect(); 1422 } catch (RemoteException e) { 1423 } 1424 } 1425 } 1426 1427 @Override 1428 public void onFailure() { 1429 // Binding failed. Oh no. 1430 Log.w(this, "onFailure - could not bind to CS for conf call %s", call.getId()); 1431 } 1432 }; 1433 1434 mBinder.bind(callback, call); 1435 } 1436 1437 handoverFailed(final Call call, final int reason)1438 void handoverFailed(final Call call, final int reason) { 1439 Log.d(this, "handoverFailed(%s) via %s.", call, getComponentName()); 1440 BindCallback callback = new BindCallback() { 1441 @Override 1442 public void onSuccess() { 1443 final String callId = mCallIdMapper.getCallId(call); 1444 // If still bound, tell the connection service create connection has failed. 1445 if (callId != null && isServiceValid("handoverFailed")) { 1446 Log.addEvent(call, LogUtils.Events.HANDOVER_FAILED, 1447 Log.piiHandle(call.getHandle())); 1448 try { 1449 mServiceInterface.handoverFailed( 1450 callId, 1451 new ConnectionRequest( 1452 call.getTargetPhoneAccount(), 1453 call.getHandle(), 1454 call.getIntentExtras(), 1455 call.getVideoState(), 1456 callId, 1457 false), 1458 reason, 1459 Log.getExternalSession(TELECOM_ABBREVIATION)); 1460 } catch (RemoteException e) { 1461 } 1462 } 1463 } 1464 1465 @Override 1466 public void onFailure() { 1467 // Binding failed. 1468 Log.w(this, "onFailure - could not bind to CS for call %s", 1469 call.getId()); 1470 } 1471 }; 1472 1473 mBinder.bind(callback, call); 1474 } 1475 handoverComplete(final Call call)1476 void handoverComplete(final Call call) { 1477 Log.d(this, "handoverComplete(%s) via %s.", call, getComponentName()); 1478 BindCallback callback = new BindCallback() { 1479 @Override 1480 public void onSuccess() { 1481 final String callId = mCallIdMapper.getCallId(call); 1482 // If still bound, tell the connection service create connection has failed. 1483 if (callId != null && isServiceValid("handoverComplete")) { 1484 try { 1485 mServiceInterface.handoverComplete( 1486 callId, 1487 Log.getExternalSession(TELECOM_ABBREVIATION)); 1488 } catch (RemoteException e) { 1489 } 1490 } 1491 } 1492 1493 @Override 1494 public void onFailure() { 1495 // Binding failed. 1496 Log.w(this, "onFailure - could not bind to CS for call %s", 1497 call.getId()); 1498 } 1499 }; 1500 1501 mBinder.bind(callback, call); 1502 } 1503 1504 /** @see IConnectionService#abort(String, Session.Info) */ abort(Call call)1505 void abort(Call call) { 1506 // Clear out any pending outgoing call data 1507 final String callId = mCallIdMapper.getCallId(call); 1508 1509 // If still bound, tell the connection service to abort. 1510 if (callId != null && isServiceValid("abort")) { 1511 try { 1512 logOutgoing("abort %s", callId); 1513 mServiceInterface.abort(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 1514 } catch (RemoteException e) { 1515 } 1516 } 1517 1518 removeCall(call, new DisconnectCause(DisconnectCause.LOCAL)); 1519 } 1520 1521 /** @see IConnectionService#silence(String, Session.Info) */ silence(Call call)1522 void silence(Call call) { 1523 final String callId = mCallIdMapper.getCallId(call); 1524 if (callId != null && isServiceValid("silence")) { 1525 try { 1526 logOutgoing("silence %s", callId); 1527 mServiceInterface.silence(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 1528 } catch (RemoteException e) { 1529 } 1530 } 1531 } 1532 1533 /** @see IConnectionService#hold(String, Session.Info) */ hold(Call call)1534 void hold(Call call) { 1535 final String callId = mCallIdMapper.getCallId(call); 1536 if (callId != null && isServiceValid("hold")) { 1537 try { 1538 logOutgoing("hold %s", callId); 1539 mServiceInterface.hold(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 1540 } catch (RemoteException e) { 1541 } 1542 } 1543 } 1544 1545 /** @see IConnectionService#unhold(String, Session.Info) */ unhold(Call call)1546 void unhold(Call call) { 1547 final String callId = mCallIdMapper.getCallId(call); 1548 if (callId != null && isServiceValid("unhold")) { 1549 try { 1550 logOutgoing("unhold %s", callId); 1551 mServiceInterface.unhold(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 1552 } catch (RemoteException e) { 1553 } 1554 } 1555 } 1556 1557 /** @see IConnectionService#onCallAudioStateChanged(String, CallAudioState, Session.Info) */ 1558 @VisibleForTesting onCallAudioStateChanged(Call activeCall, CallAudioState audioState)1559 public void onCallAudioStateChanged(Call activeCall, CallAudioState audioState) { 1560 final String callId = mCallIdMapper.getCallId(activeCall); 1561 if (callId != null && isServiceValid("onCallAudioStateChanged")) { 1562 try { 1563 logOutgoing("onCallAudioStateChanged %s %s", callId, audioState); 1564 mServiceInterface.onCallAudioStateChanged(callId, audioState, 1565 Log.getExternalSession(TELECOM_ABBREVIATION)); 1566 } catch (RemoteException e) { 1567 } 1568 } 1569 } 1570 1571 /** @see IConnectionService#disconnect(String, Session.Info) */ disconnect(Call call)1572 void disconnect(Call call) { 1573 final String callId = mCallIdMapper.getCallId(call); 1574 if (callId != null && isServiceValid("disconnect")) { 1575 try { 1576 logOutgoing("disconnect %s", callId); 1577 mServiceInterface.disconnect(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 1578 } catch (RemoteException e) { 1579 } 1580 } 1581 } 1582 1583 /** @see IConnectionService#answer(String, Session.Info) */ answer(Call call, int videoState)1584 void answer(Call call, int videoState) { 1585 final String callId = mCallIdMapper.getCallId(call); 1586 if (callId != null && isServiceValid("answer")) { 1587 try { 1588 logOutgoing("answer %s %d", callId, videoState); 1589 if (VideoProfile.isAudioOnly(videoState)) { 1590 mServiceInterface.answer(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 1591 } else { 1592 mServiceInterface.answerVideo(callId, videoState, 1593 Log.getExternalSession(TELECOM_ABBREVIATION)); 1594 } 1595 } catch (RemoteException e) { 1596 } 1597 } 1598 } 1599 1600 /** @see IConnectionService#deflect(String, Uri , Session.Info) */ deflect(Call call, Uri address)1601 void deflect(Call call, Uri address) { 1602 final String callId = mCallIdMapper.getCallId(call); 1603 if (callId != null && isServiceValid("deflect")) { 1604 try { 1605 logOutgoing("deflect %s", callId); 1606 mServiceInterface.deflect(callId, address, 1607 Log.getExternalSession(TELECOM_ABBREVIATION)); 1608 } catch (RemoteException e) { 1609 } 1610 } 1611 } 1612 1613 /** @see IConnectionService#reject(String, Session.Info) */ reject(Call call, boolean rejectWithMessage, String message)1614 void reject(Call call, boolean rejectWithMessage, String message) { 1615 final String callId = mCallIdMapper.getCallId(call); 1616 if (callId != null && isServiceValid("reject")) { 1617 try { 1618 logOutgoing("reject %s", callId); 1619 1620 if (rejectWithMessage && call.can( 1621 Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) { 1622 mServiceInterface.rejectWithMessage(callId, message, 1623 Log.getExternalSession(TELECOM_ABBREVIATION)); 1624 } else { 1625 mServiceInterface.reject(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 1626 } 1627 } catch (RemoteException e) { 1628 } 1629 } 1630 } 1631 1632 /** @see IConnectionService#reject(String, Session.Info) */ rejectWithReason(Call call, @android.telecom.Call.RejectReason int rejectReason)1633 void rejectWithReason(Call call, @android.telecom.Call.RejectReason int rejectReason) { 1634 final String callId = mCallIdMapper.getCallId(call); 1635 if (callId != null && isServiceValid("rejectReason")) { 1636 try { 1637 logOutgoing("rejectReason %s, %d", callId, rejectReason); 1638 1639 mServiceInterface.rejectWithReason(callId, rejectReason, 1640 Log.getExternalSession(TELECOM_ABBREVIATION)); 1641 } catch (RemoteException e) { 1642 } 1643 } 1644 } 1645 1646 /** @see IConnectionService#transfer(String, Uri , boolean, Session.Info) */ transfer(Call call, Uri number, boolean isConfirmationRequired)1647 void transfer(Call call, Uri number, boolean isConfirmationRequired) { 1648 final String callId = mCallIdMapper.getCallId(call); 1649 if (callId != null && isServiceValid("transfer")) { 1650 try { 1651 logOutgoing("transfer %s", callId); 1652 mServiceInterface.transfer(callId, number, isConfirmationRequired, 1653 Log.getExternalSession(TELECOM_ABBREVIATION)); 1654 } catch (RemoteException e) { 1655 } 1656 } 1657 } 1658 1659 /** @see IConnectionService#consultativeTransfer(String, String, Session.Info) */ transfer(Call call, Call otherCall)1660 void transfer(Call call, Call otherCall) { 1661 final String callId = mCallIdMapper.getCallId(call); 1662 final String otherCallId = mCallIdMapper.getCallId(otherCall); 1663 if (callId != null && otherCallId != null && isServiceValid("consultativeTransfer")) { 1664 try { 1665 logOutgoing("consultativeTransfer %s", callId); 1666 mServiceInterface.consultativeTransfer(callId, otherCallId, 1667 Log.getExternalSession(TELECOM_ABBREVIATION)); 1668 } catch (RemoteException e) { 1669 } 1670 } 1671 } 1672 1673 /** @see IConnectionService#playDtmfTone(String, char, Session.Info) */ playDtmfTone(Call call, char digit)1674 void playDtmfTone(Call call, char digit) { 1675 final String callId = mCallIdMapper.getCallId(call); 1676 if (callId != null && isServiceValid("playDtmfTone")) { 1677 try { 1678 logOutgoing("playDtmfTone %s %c", callId, digit); 1679 mServiceInterface.playDtmfTone(callId, digit, 1680 Log.getExternalSession(TELECOM_ABBREVIATION)); 1681 } catch (RemoteException e) { 1682 } 1683 } 1684 } 1685 1686 /** @see IConnectionService#stopDtmfTone(String, Session.Info) */ stopDtmfTone(Call call)1687 void stopDtmfTone(Call call) { 1688 final String callId = mCallIdMapper.getCallId(call); 1689 if (callId != null && isServiceValid("stopDtmfTone")) { 1690 try { 1691 logOutgoing("stopDtmfTone %s", callId); 1692 mServiceInterface.stopDtmfTone(callId, 1693 Log.getExternalSession(TELECOM_ABBREVIATION)); 1694 } catch (RemoteException e) { 1695 } 1696 } 1697 } 1698 addCall(Call call)1699 void addCall(Call call) { 1700 if (mCallIdMapper.getCallId(call) == null) { 1701 mCallIdMapper.addCall(call); 1702 } 1703 } 1704 1705 /** 1706 * Associates newCall with this connection service by replacing callToReplace. 1707 */ replaceCall(Call newCall, Call callToReplace)1708 void replaceCall(Call newCall, Call callToReplace) { 1709 Preconditions.checkState(callToReplace.getConnectionService() == this); 1710 mCallIdMapper.replaceCall(newCall, callToReplace); 1711 } 1712 removeCall(Call call)1713 void removeCall(Call call) { 1714 removeCall(call, new DisconnectCause(DisconnectCause.ERROR)); 1715 } 1716 removeCall(String callId, DisconnectCause disconnectCause)1717 void removeCall(String callId, DisconnectCause disconnectCause) { 1718 CreateConnectionResponse response = mPendingResponses.remove(callId); 1719 if (response != null) { 1720 response.handleCreateConnectionFailure(disconnectCause); 1721 } 1722 1723 mCallIdMapper.removeCall(callId); 1724 } 1725 removeCall(Call call, DisconnectCause disconnectCause)1726 void removeCall(Call call, DisconnectCause disconnectCause) { 1727 CreateConnectionResponse response = mPendingResponses.remove(mCallIdMapper.getCallId(call)); 1728 if (response != null) { 1729 response.handleCreateConnectionFailure(disconnectCause); 1730 } 1731 1732 mCallIdMapper.removeCall(call); 1733 } 1734 onPostDialContinue(Call call, boolean proceed)1735 void onPostDialContinue(Call call, boolean proceed) { 1736 final String callId = mCallIdMapper.getCallId(call); 1737 if (callId != null && isServiceValid("onPostDialContinue")) { 1738 try { 1739 logOutgoing("onPostDialContinue %s %b", callId, proceed); 1740 mServiceInterface.onPostDialContinue(callId, proceed, 1741 Log.getExternalSession(TELECOM_ABBREVIATION)); 1742 } catch (RemoteException ignored) { 1743 } 1744 } 1745 } 1746 conference(final Call call, Call otherCall)1747 void conference(final Call call, Call otherCall) { 1748 final String callId = mCallIdMapper.getCallId(call); 1749 final String otherCallId = mCallIdMapper.getCallId(otherCall); 1750 if (callId != null && otherCallId != null && isServiceValid("conference")) { 1751 try { 1752 logOutgoing("conference %s %s", callId, otherCallId); 1753 mServiceInterface.conference(callId, otherCallId, 1754 Log.getExternalSession(TELECOM_ABBREVIATION)); 1755 } catch (RemoteException ignored) { 1756 } 1757 } 1758 } 1759 splitFromConference(Call call)1760 void splitFromConference(Call call) { 1761 final String callId = mCallIdMapper.getCallId(call); 1762 if (callId != null && isServiceValid("splitFromConference")) { 1763 try { 1764 logOutgoing("splitFromConference %s", callId); 1765 mServiceInterface.splitFromConference(callId, 1766 Log.getExternalSession(TELECOM_ABBREVIATION)); 1767 } catch (RemoteException ignored) { 1768 } 1769 } 1770 } 1771 mergeConference(Call call)1772 void mergeConference(Call call) { 1773 final String callId = mCallIdMapper.getCallId(call); 1774 if (callId != null && isServiceValid("mergeConference")) { 1775 try { 1776 logOutgoing("mergeConference %s", callId); 1777 mServiceInterface.mergeConference(callId, 1778 Log.getExternalSession(TELECOM_ABBREVIATION)); 1779 } catch (RemoteException ignored) { 1780 } 1781 } 1782 } 1783 swapConference(Call call)1784 void swapConference(Call call) { 1785 final String callId = mCallIdMapper.getCallId(call); 1786 if (callId != null && isServiceValid("swapConference")) { 1787 try { 1788 logOutgoing("swapConference %s", callId); 1789 mServiceInterface.swapConference(callId, 1790 Log.getExternalSession(TELECOM_ABBREVIATION)); 1791 } catch (RemoteException ignored) { 1792 } 1793 } 1794 } 1795 addConferenceParticipants(Call call, List<Uri> participants)1796 void addConferenceParticipants(Call call, List<Uri> participants) { 1797 final String callId = mCallIdMapper.getCallId(call); 1798 if (callId != null && isServiceValid("addConferenceParticipants")) { 1799 try { 1800 logOutgoing("addConferenceParticipants %s", callId); 1801 mServiceInterface.addConferenceParticipants(callId, participants, 1802 Log.getExternalSession(TELECOM_ABBREVIATION)); 1803 } catch (RemoteException ignored) { 1804 } 1805 } 1806 } 1807 1808 @VisibleForTesting pullExternalCall(Call call)1809 public void pullExternalCall(Call call) { 1810 final String callId = mCallIdMapper.getCallId(call); 1811 if (callId != null && isServiceValid("pullExternalCall")) { 1812 try { 1813 logOutgoing("pullExternalCall %s", callId); 1814 mServiceInterface.pullExternalCall(callId, 1815 Log.getExternalSession(TELECOM_ABBREVIATION)); 1816 } catch (RemoteException ignored) { 1817 } 1818 } 1819 } 1820 sendCallEvent(Call call, String event, Bundle extras)1821 void sendCallEvent(Call call, String event, Bundle extras) { 1822 final String callId = mCallIdMapper.getCallId(call); 1823 if (callId != null && isServiceValid("sendCallEvent")) { 1824 try { 1825 logOutgoing("sendCallEvent %s %s", callId, event); 1826 mServiceInterface.sendCallEvent(callId, event, extras, 1827 Log.getExternalSession(TELECOM_ABBREVIATION)); 1828 } catch (RemoteException ignored) { 1829 } 1830 } 1831 } 1832 onExtrasChanged(Call call, Bundle extras)1833 void onExtrasChanged(Call call, Bundle extras) { 1834 final String callId = mCallIdMapper.getCallId(call); 1835 if (callId != null && isServiceValid("onExtrasChanged")) { 1836 try { 1837 logOutgoing("onExtrasChanged %s %s", callId, extras); 1838 mServiceInterface.onExtrasChanged(callId, extras, 1839 Log.getExternalSession(TELECOM_ABBREVIATION)); 1840 } catch (RemoteException ignored) { 1841 } 1842 } 1843 } 1844 startRtt(Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall)1845 void startRtt(Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall) { 1846 final String callId = mCallIdMapper.getCallId(call); 1847 if (callId != null && isServiceValid("startRtt")) { 1848 try { 1849 logOutgoing("startRtt: %s %s %s", callId, fromInCall, toInCall); 1850 mServiceInterface.startRtt(callId, fromInCall, toInCall, 1851 Log.getExternalSession(TELECOM_ABBREVIATION)); 1852 } catch (RemoteException ignored) { 1853 } 1854 } 1855 } 1856 stopRtt(Call call)1857 void stopRtt(Call call) { 1858 final String callId = mCallIdMapper.getCallId(call); 1859 if (callId != null && isServiceValid("stopRtt")) { 1860 try { 1861 logOutgoing("stopRtt: %s", callId); 1862 mServiceInterface.stopRtt(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 1863 } catch (RemoteException ignored) { 1864 } 1865 } 1866 } 1867 respondToRttRequest( Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall)1868 void respondToRttRequest( 1869 Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall) { 1870 final String callId = mCallIdMapper.getCallId(call); 1871 if (callId != null && isServiceValid("respondToRttRequest")) { 1872 try { 1873 logOutgoing("respondToRttRequest: %s %s %s", callId, fromInCall, toInCall); 1874 mServiceInterface.respondToRttUpgradeRequest( 1875 callId, fromInCall, toInCall, Log.getExternalSession(TELECOM_ABBREVIATION)); 1876 } catch (RemoteException ignored) { 1877 } 1878 } 1879 } 1880 1881 /** {@inheritDoc} */ 1882 @Override setServiceInterface(IBinder binder)1883 protected void setServiceInterface(IBinder binder) { 1884 mServiceInterface = IConnectionService.Stub.asInterface(binder); 1885 Log.v(this, "Adding Connection Service Adapter."); 1886 addConnectionServiceAdapter(mAdapter); 1887 } 1888 1889 /** {@inheritDoc} */ 1890 @Override removeServiceInterface()1891 protected void removeServiceInterface() { 1892 Log.v(this, "Removing Connection Service Adapter."); 1893 removeConnectionServiceAdapter(mAdapter); 1894 // We have lost our service connection. Notify the world that this service is done. 1895 // We must notify the adapter before CallsManager. The adapter will force any pending 1896 // outgoing calls to try the next service. This needs to happen before CallsManager 1897 // tries to clean up any calls still associated with this service. 1898 handleConnectionServiceDeath(); 1899 mCallsManager.handleConnectionServiceDeath(this); 1900 mServiceInterface = null; 1901 } 1902 1903 @Override connectionServiceFocusLost()1904 public void connectionServiceFocusLost() { 1905 // Immediately response to the Telecom that it has released the call resources. 1906 // TODO(mpq): Change back to the default implementation once b/69651192 done. 1907 if (mConnSvrFocusListener != null) { 1908 mConnSvrFocusListener.onConnectionServiceReleased(ConnectionServiceWrapper.this); 1909 } 1910 BindCallback callback = new BindCallback() { 1911 @Override 1912 public void onSuccess() { 1913 try { 1914 mServiceInterface.connectionServiceFocusLost( 1915 Log.getExternalSession(TELECOM_ABBREVIATION)); 1916 } catch (RemoteException ignored) { 1917 Log.d(this, "failed to inform the focus lost event"); 1918 } 1919 } 1920 1921 @Override 1922 public void onFailure() {} 1923 }; 1924 mBinder.bind(callback, null /* null call */); 1925 } 1926 1927 @Override connectionServiceFocusGained()1928 public void connectionServiceFocusGained() { 1929 BindCallback callback = new BindCallback() { 1930 @Override 1931 public void onSuccess() { 1932 try { 1933 mServiceInterface.connectionServiceFocusGained( 1934 Log.getExternalSession(TELECOM_ABBREVIATION)); 1935 } catch (RemoteException ignored) { 1936 Log.d(this, "failed to inform the focus gained event"); 1937 } 1938 } 1939 1940 @Override 1941 public void onFailure() {} 1942 }; 1943 mBinder.bind(callback, null /* null call */); 1944 } 1945 1946 @Override setConnectionServiceFocusListener( ConnectionServiceFocusManager.ConnectionServiceFocusListener listener)1947 public void setConnectionServiceFocusListener( 1948 ConnectionServiceFocusManager.ConnectionServiceFocusListener listener) { 1949 mConnSvrFocusListener = listener; 1950 } 1951 handleCreateConnectionComplete( String callId, ConnectionRequest request, ParcelableConnection connection)1952 private void handleCreateConnectionComplete( 1953 String callId, 1954 ConnectionRequest request, 1955 ParcelableConnection connection) { 1956 // TODO: Note we are not using parameter "request", which is a side effect of our tacit 1957 // assumption that we have at most one outgoing connection attempt per ConnectionService. 1958 // This may not continue to be the case. 1959 if (connection.getState() == Connection.STATE_DISCONNECTED) { 1960 // A connection that begins in the DISCONNECTED state is an indication of 1961 // failure to connect; we handle all failures uniformly 1962 Call foundCall = mCallIdMapper.getCall(callId); 1963 1964 if (connection.getConnectTimeMillis() != 0) { 1965 foundCall.setConnectTimeMillis(connection.getConnectTimeMillis()); 1966 } 1967 1968 if (foundCall != null) { 1969 // The post-dial digits are created when the call is first created. Normally 1970 // the ConnectionService is responsible for stripping them from the address, but 1971 // since a failed connection will not have done this, we could end up with duplicate 1972 // post-dial digits. 1973 foundCall.clearPostDialDigits(); 1974 } 1975 removeCall(callId, connection.getDisconnectCause()); 1976 } else { 1977 // Successful connection 1978 if (mPendingResponses.containsKey(callId)) { 1979 mPendingResponses.remove(callId) 1980 .handleCreateConnectionSuccess(mCallIdMapper, connection); 1981 } 1982 } 1983 } 1984 handleCreateConferenceComplete( String callId, ConnectionRequest request, ParcelableConference conference)1985 private void handleCreateConferenceComplete( 1986 String callId, 1987 ConnectionRequest request, 1988 ParcelableConference conference) { 1989 // TODO: Note we are not using parameter "request", which is a side effect of our tacit 1990 // assumption that we have at most one outgoing conference attempt per ConnectionService. 1991 // This may not continue to be the case. 1992 if (conference.getState() == Connection.STATE_DISCONNECTED) { 1993 // A conference that begins in the DISCONNECTED state is an indication of 1994 // failure to connect; we handle all failures uniformly 1995 removeCall(callId, conference.getDisconnectCause()); 1996 } else { 1997 // Successful connection 1998 if (mPendingResponses.containsKey(callId)) { 1999 mPendingResponses.remove(callId) 2000 .handleCreateConferenceSuccess(mCallIdMapper, conference); 2001 } 2002 } 2003 } 2004 2005 /** 2006 * Called when the associated connection service dies. 2007 */ handleConnectionServiceDeath()2008 private void handleConnectionServiceDeath() { 2009 if (!mPendingResponses.isEmpty()) { 2010 CreateConnectionResponse[] responses = mPendingResponses.values().toArray( 2011 new CreateConnectionResponse[mPendingResponses.values().size()]); 2012 mPendingResponses.clear(); 2013 for (int i = 0; i < responses.length; i++) { 2014 responses[i].handleCreateConnectionFailure( 2015 new DisconnectCause(DisconnectCause.ERROR, "CS_DEATH")); 2016 } 2017 } 2018 mCallIdMapper.clear(); 2019 2020 if (mConnSvrFocusListener != null) { 2021 mConnSvrFocusListener.onConnectionServiceDeath(this); 2022 } 2023 } 2024 logIncoming(String msg, Object... params)2025 private void logIncoming(String msg, Object... params) { 2026 // Keep these as debug; the incoming logging is traced on a package level through the 2027 // session logging. 2028 Log.d(this, "CS -> TC[" + Log.getPackageAbbreviation(mComponentName) + "]: " 2029 + msg, params); 2030 } 2031 logOutgoing(String msg, Object... params)2032 private void logOutgoing(String msg, Object... params) { 2033 Log.d(this, "TC -> CS[" + Log.getPackageAbbreviation(mComponentName) + "]: " 2034 + msg, params); 2035 } 2036 queryRemoteConnectionServices(final UserHandle userHandle, final String callingPackage, final RemoteServiceCallback callback)2037 private void queryRemoteConnectionServices(final UserHandle userHandle, 2038 final String callingPackage, final RemoteServiceCallback callback) { 2039 boolean isCallerConnectionManager = false; 2040 // For each Sim ConnectionService, use its subid to find the correct connection manager for 2041 // that ConnectionService; return those Sim ConnectionServices which match the connection 2042 // manager. 2043 final Set<ConnectionServiceWrapper> simServices = Collections.newSetFromMap( 2044 new ConcurrentHashMap<ConnectionServiceWrapper, Boolean>(8, 0.9f, 1)); 2045 for (PhoneAccountHandle handle : mPhoneAccountRegistrar.getSimPhoneAccounts(userHandle)) { 2046 int subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(handle); 2047 PhoneAccountHandle connectionMgrHandle = mPhoneAccountRegistrar.getSimCallManager(subId, 2048 userHandle); 2049 if (connectionMgrHandle == null 2050 || !connectionMgrHandle.getComponentName().getPackageName().equals( 2051 callingPackage)) { 2052 Log.v(this, "queryRemoteConnectionServices: callingPackage=%s skipped; " 2053 + "doesn't match mgr %s for tfa %s", 2054 callingPackage, connectionMgrHandle, handle); 2055 } else { 2056 isCallerConnectionManager = true; 2057 } 2058 ConnectionServiceWrapper service = mConnectionServiceRepository.getService( 2059 handle.getComponentName(), handle.getUserHandle()); 2060 if (service != null && service != this) { 2061 simServices.add(service); 2062 } else { 2063 // This is unexpected, normally PhoneAccounts with CAPABILITY_CALL_PROVIDER are not 2064 // also CAPABILITY_CONNECTION_MANAGER 2065 Log.w(this, "call provider also detected as SIM call manager: " + service); 2066 } 2067 } 2068 2069 // Bail early if the caller isn't the sim connection mgr. 2070 if (!isCallerConnectionManager) { 2071 Log.d(this, "queryRemoteConnectionServices: none; not sim call mgr."); 2072 noRemoteServices(callback); 2073 return; 2074 } 2075 2076 final List<ComponentName> simServiceComponentNames = new ArrayList<>(); 2077 final List<IBinder> simServiceBinders = new ArrayList<>(); 2078 2079 Log.i(this, "queryRemoteConnectionServices, simServices = %s", simServices); 2080 2081 for (ConnectionServiceWrapper simService : simServices) { 2082 final ConnectionServiceWrapper currentSimService = simService; 2083 2084 currentSimService.mBinder.bind(new BindCallback() { 2085 @Override 2086 public void onSuccess() { 2087 Log.d(this, "queryRemoteConnectionServices: Adding simService %s", 2088 currentSimService.getComponentName()); 2089 if (currentSimService.mServiceInterface == null) { 2090 // The remote ConnectionService died, so do not add it. 2091 // We will still perform maybeComplete() and notify the caller with an empty 2092 // list of sim services via maybeComplete(). 2093 Log.w(this, "queryRemoteConnectionServices: simService %s died - Skipping.", 2094 currentSimService.getComponentName()); 2095 } else { 2096 simServiceComponentNames.add(currentSimService.getComponentName()); 2097 simServiceBinders.add(currentSimService.mServiceInterface.asBinder()); 2098 } 2099 maybeComplete(); 2100 } 2101 2102 @Override 2103 public void onFailure() { 2104 Log.d(this, "queryRemoteConnectionServices: Failed simService %s", 2105 currentSimService.getComponentName()); 2106 // We know maybeComplete() will always be a no-op from now on, so go ahead and 2107 // signal failure of the entire request 2108 noRemoteServices(callback); 2109 } 2110 2111 private void maybeComplete() { 2112 if (simServiceComponentNames.size() == simServices.size()) { 2113 setRemoteServices(callback, simServiceComponentNames, simServiceBinders); 2114 } 2115 } 2116 }, null); 2117 } 2118 } 2119 setRemoteServices( RemoteServiceCallback callback, List<ComponentName> componentNames, List<IBinder> binders)2120 private void setRemoteServices( 2121 RemoteServiceCallback callback, 2122 List<ComponentName> componentNames, 2123 List<IBinder> binders) { 2124 try { 2125 callback.onResult(componentNames, binders); 2126 } catch (RemoteException e) { 2127 Log.e(this, e, "setRemoteServices: Contacting ConnectionService %s", 2128 ConnectionServiceWrapper.this.getComponentName()); 2129 } 2130 } 2131 noRemoteServices(RemoteServiceCallback callback)2132 private void noRemoteServices(RemoteServiceCallback callback) { 2133 setRemoteServices(callback, Collections.EMPTY_LIST, Collections.EMPTY_LIST); 2134 } 2135 2136 @Override toString()2137 public String toString() { 2138 StringBuilder sb = new StringBuilder(); 2139 sb.append("[ConnectionServiceWrapper componentName="); 2140 sb.append(mComponentName); 2141 sb.append("]"); 2142 return sb.toString(); 2143 } 2144 } 2145