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 android.app.AppOpsManager; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.net.Uri; 23 import android.os.Binder; 24 import android.os.Bundle; 25 import android.os.IBinder; 26 import android.os.ParcelFileDescriptor; 27 import android.os.RemoteException; 28 import android.os.UserHandle; 29 import android.telecom.CallAudioState; 30 import android.telecom.Connection; 31 import android.telecom.ConnectionRequest; 32 import android.telecom.ConnectionService; 33 import android.telecom.DisconnectCause; 34 import android.telecom.GatewayInfo; 35 import android.telecom.Log; 36 import android.telecom.Logging.Session; 37 import android.telecom.ParcelableConference; 38 import android.telecom.ParcelableConnection; 39 import android.telecom.PhoneAccountHandle; 40 import android.telecom.StatusHints; 41 import android.telecom.TelecomManager; 42 import android.telecom.VideoProfile; 43 44 import com.android.internal.annotations.VisibleForTesting; 45 import com.android.internal.telecom.IConnectionService; 46 import com.android.internal.telecom.IConnectionServiceAdapter; 47 import com.android.internal.telecom.IVideoProvider; 48 import com.android.internal.telecom.RemoteServiceCallback; 49 import com.android.internal.util.Preconditions; 50 51 import java.util.ArrayList; 52 import java.util.Collections; 53 import java.util.HashMap; 54 import java.util.List; 55 import java.util.Map; 56 import java.util.Set; 57 import java.util.concurrent.ConcurrentHashMap; 58 59 /** 60 * Wrapper for {@link IConnectionService}s, handles binding to {@link IConnectionService} and keeps 61 * track of when the object can safely be unbound. Other classes should not use 62 * {@link IConnectionService} directly and instead should use this class to invoke methods of 63 * {@link IConnectionService}. 64 */ 65 @VisibleForTesting 66 public class ConnectionServiceWrapper extends ServiceBinder { 67 68 private final class Adapter extends IConnectionServiceAdapter.Stub { 69 70 @Override 71 public void handleCreateConnectionComplete(String callId, ConnectionRequest request, 72 ParcelableConnection connection, Session.Info sessionInfo) { 73 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_HANDLE_CREATE_CONNECTION_COMPLETE); 74 long token = Binder.clearCallingIdentity(); 75 try { 76 synchronized (mLock) { 77 logIncoming("handleCreateConnectionComplete %s", callId); 78 ConnectionServiceWrapper.this 79 .handleCreateConnectionComplete(callId, request, connection); 80 81 if (mServiceInterface != null) { 82 logOutgoing("createConnectionComplete %s", callId); 83 try { 84 mServiceInterface.createConnectionComplete(callId, 85 Log.getExternalSession()); 86 } catch (RemoteException e) { 87 } 88 } 89 } 90 } finally { 91 Binder.restoreCallingIdentity(token); 92 Log.endSession(); 93 } 94 } 95 96 @Override 97 public void setActive(String callId, Session.Info sessionInfo) { 98 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_ACTIVE); 99 long token = Binder.clearCallingIdentity(); 100 try { 101 synchronized (mLock) { 102 logIncoming("setActive %s", callId); 103 Call call = mCallIdMapper.getCall(callId); 104 if (call != null) { 105 mCallsManager.markCallAsActive(call); 106 } else { 107 // Log.w(this, "setActive, unknown call id: %s", msg.obj); 108 } 109 } 110 } finally { 111 Binder.restoreCallingIdentity(token); 112 Log.endSession(); 113 } 114 } 115 116 @Override 117 public void setRinging(String callId, Session.Info sessionInfo) { 118 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_RINGING); 119 long token = Binder.clearCallingIdentity(); 120 try { 121 synchronized (mLock) { 122 logIncoming("setRinging %s", callId); 123 Call call = mCallIdMapper.getCall(callId); 124 if (call != null) { 125 mCallsManager.markCallAsRinging(call); 126 } else { 127 // Log.w(this, "setRinging, unknown call id: %s", msg.obj); 128 } 129 } 130 } finally { 131 Binder.restoreCallingIdentity(token); 132 Log.endSession(); 133 } 134 } 135 136 @Override 137 public void setVideoProvider(String callId, IVideoProvider videoProvider, 138 Session.Info sessionInfo) { 139 Log.startSession(sessionInfo, "CSW.sVP"); 140 long token = Binder.clearCallingIdentity(); 141 try { 142 synchronized (mLock) { 143 logIncoming("setVideoProvider %s", callId); 144 Call call = mCallIdMapper.getCall(callId); 145 if (call != null) { 146 call.setVideoProvider(videoProvider); 147 } 148 } 149 } finally { 150 Binder.restoreCallingIdentity(token); 151 Log.endSession(); 152 } 153 } 154 155 @Override 156 public void setDialing(String callId, Session.Info sessionInfo) { 157 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_DIALING); 158 long token = Binder.clearCallingIdentity(); 159 try { 160 synchronized (mLock) { 161 logIncoming("setDialing %s", callId); 162 Call call = mCallIdMapper.getCall(callId); 163 if (call != null) { 164 mCallsManager.markCallAsDialing(call); 165 } else { 166 // Log.w(this, "setDialing, unknown call id: %s", msg.obj); 167 } 168 } 169 } finally { 170 Binder.restoreCallingIdentity(token); 171 Log.endSession(); 172 } 173 } 174 175 @Override 176 public void setPulling(String callId, Session.Info sessionInfo) { 177 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_PULLING); 178 long token = Binder.clearCallingIdentity(); 179 try { 180 synchronized (mLock) { 181 logIncoming("setPulling %s", callId); 182 Call call = mCallIdMapper.getCall(callId); 183 if (call != null) { 184 mCallsManager.markCallAsPulling(call); 185 } 186 } 187 } finally { 188 Binder.restoreCallingIdentity(token); 189 Log.endSession(); 190 } 191 } 192 193 @Override 194 public void setDisconnected(String callId, DisconnectCause disconnectCause, 195 Session.Info sessionInfo) { 196 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_DISCONNECTED); 197 long token = Binder.clearCallingIdentity(); 198 try { 199 synchronized (mLock) { 200 logIncoming("setDisconnected %s %s", callId, disconnectCause); 201 Call call = mCallIdMapper.getCall(callId); 202 Log.d(this, "disconnect call %s %s", disconnectCause, call); 203 if (call != null) { 204 mCallsManager.markCallAsDisconnected(call, disconnectCause); 205 } else { 206 // Log.w(this, "setDisconnected, unknown call id: %s", args.arg1); 207 } 208 } 209 } finally { 210 Binder.restoreCallingIdentity(token); 211 Log.endSession(); 212 } 213 } 214 215 @Override 216 public void setOnHold(String callId, Session.Info sessionInfo) { 217 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_ON_HOLD); 218 long token = Binder.clearCallingIdentity(); 219 try { 220 synchronized (mLock) { 221 logIncoming("setOnHold %s", callId); 222 Call call = mCallIdMapper.getCall(callId); 223 if (call != null) { 224 mCallsManager.markCallAsOnHold(call); 225 } else { 226 // Log.w(this, "setOnHold, unknown call id: %s", msg.obj); 227 } 228 } 229 } finally { 230 Binder.restoreCallingIdentity(token); 231 Log.endSession(); 232 } 233 } 234 235 @Override 236 public void setRingbackRequested(String callId, boolean ringback, 237 Session.Info sessionInfo) { 238 Log.startSession(sessionInfo, "CSW.SRR"); 239 long token = Binder.clearCallingIdentity(); 240 try { 241 synchronized (mLock) { 242 logIncoming("setRingbackRequested %s %b", callId, ringback); 243 Call call = mCallIdMapper.getCall(callId); 244 if (call != null) { 245 call.setRingbackRequested(ringback); 246 } else { 247 // Log.w(this, "setRingback, unknown call id: %s", args.arg1); 248 } 249 } 250 } finally { 251 Binder.restoreCallingIdentity(token); 252 Log.endSession(); 253 } 254 } 255 256 @Override 257 public void removeCall(String callId, Session.Info sessionInfo) { 258 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_REMOVE_CALL); 259 long token = Binder.clearCallingIdentity(); 260 try { 261 synchronized (mLock) { 262 logIncoming("removeCall %s", callId); 263 Call call = mCallIdMapper.getCall(callId); 264 if (call != null) { 265 if (call.isAlive()) { 266 mCallsManager.markCallAsDisconnected( 267 call, new DisconnectCause(DisconnectCause.REMOTE)); 268 } else { 269 mCallsManager.markCallAsRemoved(call); 270 } 271 } 272 } 273 } finally { 274 Binder.restoreCallingIdentity(token); 275 Log.endSession(); 276 } 277 } 278 279 @Override 280 public void setConnectionCapabilities(String callId, int connectionCapabilities, 281 Session.Info sessionInfo) { 282 Log.startSession(sessionInfo, "CSW.sCC"); 283 long token = Binder.clearCallingIdentity(); 284 try { 285 synchronized (mLock) { 286 logIncoming("setConnectionCapabilities %s %d", callId, connectionCapabilities); 287 Call call = mCallIdMapper.getCall(callId); 288 if (call != null) { 289 call.setConnectionCapabilities(connectionCapabilities); 290 } else { 291 // Log.w(ConnectionServiceWrapper.this, 292 // "setConnectionCapabilities, unknown call id: %s", msg.obj); 293 } 294 } 295 } finally { 296 Binder.restoreCallingIdentity(token); 297 Log.endSession(); 298 } 299 } 300 301 @Override 302 public void setConnectionProperties(String callId, int connectionProperties, 303 Session.Info sessionInfo) { 304 Log.startSession("CSW.sCP"); 305 long token = Binder.clearCallingIdentity(); 306 try { 307 synchronized (mLock) { 308 logIncoming("setConnectionProperties %s %d", callId, connectionProperties); 309 Call call = mCallIdMapper.getCall(callId); 310 if (call != null) { 311 call.setConnectionProperties(connectionProperties); 312 } 313 } 314 } finally { 315 Binder.restoreCallingIdentity(token); 316 Log.endSession(); 317 } 318 } 319 320 @Override 321 public void setIsConferenced(String callId, String conferenceCallId, 322 Session.Info sessionInfo) { 323 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_SET_IS_CONFERENCED); 324 long token = Binder.clearCallingIdentity(); 325 try { 326 synchronized (mLock) { 327 logIncoming("setIsConferenced %s %s", callId, conferenceCallId); 328 Call childCall = mCallIdMapper.getCall(callId); 329 if (childCall != null) { 330 if (conferenceCallId == null) { 331 Log.d(this, "unsetting parent: %s", conferenceCallId); 332 childCall.setParentAndChildCall(null); 333 } else { 334 Call conferenceCall = mCallIdMapper.getCall(conferenceCallId); 335 childCall.setParentAndChildCall(conferenceCall); 336 } 337 } else { 338 // Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1); 339 } 340 } 341 } finally { 342 Binder.restoreCallingIdentity(token); 343 Log.endSession(); 344 } 345 } 346 347 @Override 348 public void setConferenceMergeFailed(String callId, Session.Info sessionInfo) { 349 Log.startSession(sessionInfo, "CSW.sCMF"); 350 long token = Binder.clearCallingIdentity(); 351 try { 352 synchronized (mLock) { 353 logIncoming("setConferenceMergeFailed %s", callId); 354 // TODO: we should move the UI for indication a merge failure here 355 // from CallNotifier.onSuppServiceFailed(). This way the InCallUI can 356 // deliver the message anyway that they want. b/20530631. 357 Call call = mCallIdMapper.getCall(callId); 358 if (call != null) { 359 call.onConnectionEvent(Connection.EVENT_CALL_MERGE_FAILED, null); 360 } else { 361 Log.w(this, "setConferenceMergeFailed, unknown call id: %s", callId); 362 } 363 } 364 } finally { 365 Binder.restoreCallingIdentity(token); 366 Log.endSession(); 367 } 368 } 369 370 @Override 371 public void addConferenceCall(String callId, ParcelableConference parcelableConference, 372 Session.Info sessionInfo) { 373 Log.startSession(sessionInfo, LogUtils.Sessions.CSW_ADD_CONFERENCE_CALL); 374 long token = Binder.clearCallingIdentity(); 375 try { 376 synchronized (mLock) { 377 if (mCallIdMapper.getCall(callId) != null) { 378 Log.w(this, "Attempting to add a conference call using an existing " + 379 "call id %s", callId); 380 return; 381 } 382 logIncoming("addConferenceCall %s %s [%s]", callId, parcelableConference, 383 parcelableConference.getConnectionIds()); 384 385 // Make sure that there's at least one valid call. For remote connections 386 // we'll get a add conference msg from both the remote connection service 387 // and from the real connection service. 388 boolean hasValidCalls = false; 389 for (String connId : parcelableConference.getConnectionIds()) { 390 if (mCallIdMapper.getCall(connId) != null) { 391 hasValidCalls = true; 392 } 393 } 394 // But don't bail out if the connection count is 0, because that is a valid 395 // IMS conference state. 396 if (!hasValidCalls && parcelableConference.getConnectionIds().size() > 0) { 397 Log.d(this, "Attempting to add a conference with no valid calls"); 398 return; 399 } 400 401 PhoneAccountHandle phAcc = null; 402 if (parcelableConference != null && 403 parcelableConference.getPhoneAccount() != null) { 404 phAcc = parcelableConference.getPhoneAccount(); 405 } 406 407 Bundle connectionExtras = parcelableConference.getExtras(); 408 409 String connectIdToCheck = null; 410 if (connectionExtras != null && connectionExtras 411 .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) { 412 // Conference was added via a connection manager, see if its original id is 413 // known. 414 connectIdToCheck = connectionExtras 415 .getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID); 416 } else { 417 connectIdToCheck = callId; 418 } 419 420 Call conferenceCall; 421 // Check to see if this conference has already been added. 422 Call alreadyAddedConnection = mCallsManager 423 .getAlreadyAddedConnection(connectIdToCheck); 424 if (alreadyAddedConnection != null && mCallIdMapper.getCall(callId) == null) { 425 // We are currently attempting to add the conference via a connection mgr, 426 // and the originating ConnectionService has already added it. Instead of 427 // making a new Telecom call, we will simply add it to the ID mapper here, 428 // and replace the ConnectionService on the call. 429 mCallIdMapper.addCall(alreadyAddedConnection, callId); 430 alreadyAddedConnection.replaceConnectionService( 431 ConnectionServiceWrapper.this); 432 conferenceCall = alreadyAddedConnection; 433 } else { 434 // need to create a new Call 435 Call newConferenceCall = mCallsManager.createConferenceCall(callId, 436 phAcc, parcelableConference); 437 mCallIdMapper.addCall(newConferenceCall, callId); 438 newConferenceCall.setConnectionService(ConnectionServiceWrapper.this); 439 conferenceCall = newConferenceCall; 440 } 441 442 Log.d(this, "adding children to conference %s phAcc %s", 443 parcelableConference.getConnectionIds(), phAcc); 444 for (String connId : parcelableConference.getConnectionIds()) { 445 Call childCall = mCallIdMapper.getCall(connId); 446 Log.d(this, "found child: %s", connId); 447 if (childCall != null) { 448 childCall.setParentAndChildCall(conferenceCall); 449 } 450 } 451 } 452 } finally { 453 Binder.restoreCallingIdentity(token); 454 Log.endSession(); 455 } 456 } 457 458 @Override 459 public void onPostDialWait(String callId, String remaining, 460 Session.Info sessionInfo) throws RemoteException { 461 Log.startSession(sessionInfo, "CSW.oPDW"); 462 long token = Binder.clearCallingIdentity(); 463 try { 464 synchronized (mLock) { 465 logIncoming("onPostDialWait %s %s", callId, remaining); 466 Call call = mCallIdMapper.getCall(callId); 467 if (call != null) { 468 call.onPostDialWait(remaining); 469 } else { 470 // Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1); 471 } 472 } 473 } finally { 474 Binder.restoreCallingIdentity(token); 475 Log.endSession(); 476 } 477 } 478 479 @Override 480 public void onPostDialChar(String callId, char nextChar, 481 Session.Info sessionInfo) throws RemoteException { 482 Log.startSession(sessionInfo, "CSW.oPDC"); 483 long token = Binder.clearCallingIdentity(); 484 try { 485 synchronized (mLock) { 486 logIncoming("onPostDialChar %s %s", callId, nextChar); 487 Call call = mCallIdMapper.getCall(callId); 488 if (call != null) { 489 call.onPostDialChar(nextChar); 490 } else { 491 // Log.w(this, "onPostDialChar, unknown call id: %s", args.arg1); 492 } 493 } 494 } finally { 495 Binder.restoreCallingIdentity(token); 496 Log.endSession(); 497 } 498 } 499 500 @Override 501 public void queryRemoteConnectionServices(RemoteServiceCallback callback, 502 Session.Info sessionInfo) { 503 final UserHandle callingUserHandle = Binder.getCallingUserHandle(); 504 Log.startSession(sessionInfo, "CSW.qRCS"); 505 long token = Binder.clearCallingIdentity(); 506 try { 507 synchronized (mLock) { 508 logIncoming("queryRemoteConnectionServices %s", callback); 509 ConnectionServiceWrapper.this 510 .queryRemoteConnectionServices(callingUserHandle, callback); 511 } 512 } finally { 513 Binder.restoreCallingIdentity(token); 514 Log.endSession(); 515 } 516 } 517 518 @Override 519 public void setVideoState(String callId, int videoState, Session.Info sessionInfo) { 520 Log.startSession(sessionInfo, "CSW.sVS"); 521 long token = Binder.clearCallingIdentity(); 522 try { 523 synchronized (mLock) { 524 logIncoming("setVideoState %s %d", callId, videoState); 525 Call call = mCallIdMapper.getCall(callId); 526 if (call != null) { 527 call.setVideoState(videoState); 528 } 529 } 530 } finally { 531 Binder.restoreCallingIdentity(token); 532 Log.endSession(); 533 } 534 } 535 536 @Override 537 public void setIsVoipAudioMode(String callId, boolean isVoip, Session.Info sessionInfo) { 538 Log.startSession(sessionInfo, "CSW.sIVAM"); 539 long token = Binder.clearCallingIdentity(); 540 try { 541 synchronized (mLock) { 542 logIncoming("setIsVoipAudioMode %s %b", callId, isVoip); 543 Call call = mCallIdMapper.getCall(callId); 544 if (call != null) { 545 call.setIsVoipAudioMode(isVoip); 546 } 547 } 548 } finally { 549 Binder.restoreCallingIdentity(token); 550 Log.endSession(); 551 } 552 } 553 554 @Override 555 public void setAudioRoute(String callId, int audioRoute, Session.Info sessionInfo) { 556 Log.startSession(sessionInfo, "CSW.sAR"); 557 long token = Binder.clearCallingIdentity(); 558 try { 559 synchronized (mLock) { 560 logIncoming("setAudioRoute %s %s", callId, 561 CallAudioState.audioRouteToString(audioRoute)); 562 mCallsManager.setAudioRoute(audioRoute); 563 } 564 } finally { 565 Binder.restoreCallingIdentity(token); 566 Log.endSession(); 567 } 568 } 569 570 @Override 571 public void setStatusHints(String callId, StatusHints statusHints, 572 Session.Info sessionInfo) { 573 Log.startSession(sessionInfo, "CSW.sSH"); 574 long token = Binder.clearCallingIdentity(); 575 try { 576 synchronized (mLock) { 577 logIncoming("setStatusHints %s %s", callId, statusHints); 578 Call call = mCallIdMapper.getCall(callId); 579 if (call != null) { 580 call.setStatusHints(statusHints); 581 } 582 } 583 } finally { 584 Binder.restoreCallingIdentity(token); 585 Log.endSession(); 586 } 587 } 588 589 @Override 590 public void putExtras(String callId, Bundle extras, Session.Info sessionInfo) { 591 Log.startSession(sessionInfo, "CSW.pE"); 592 long token = Binder.clearCallingIdentity(); 593 try { 594 synchronized (mLock) { 595 Bundle.setDefusable(extras, true); 596 Call call = mCallIdMapper.getCall(callId); 597 if (call != null) { 598 call.putExtras(Call.SOURCE_CONNECTION_SERVICE, extras); 599 } 600 } 601 } finally { 602 Binder.restoreCallingIdentity(token); 603 Log.endSession(); 604 } 605 } 606 607 @Override 608 public void removeExtras(String callId, List<String> keys, Session.Info sessionInfo) { 609 Log.startSession(sessionInfo, "CSW.rE"); 610 long token = Binder.clearCallingIdentity(); 611 try { 612 synchronized (mLock) { 613 logIncoming("removeExtra %s %s", callId, keys); 614 Call call = mCallIdMapper.getCall(callId); 615 if (call != null) { 616 call.removeExtras(Call.SOURCE_CONNECTION_SERVICE, keys); 617 } 618 } 619 } finally { 620 Binder.restoreCallingIdentity(token); 621 Log.endSession(); 622 } 623 } 624 625 @Override 626 public void setAddress(String callId, Uri address, int presentation, 627 Session.Info sessionInfo) { 628 Log.startSession(sessionInfo, "CSW.sA"); 629 long token = Binder.clearCallingIdentity(); 630 try { 631 synchronized (mLock) { 632 logIncoming("setAddress %s %s %d", callId, address, presentation); 633 Call call = mCallIdMapper.getCall(callId); 634 if (call != null) { 635 call.setHandle(address, presentation); 636 } 637 } 638 } finally { 639 Binder.restoreCallingIdentity(token); 640 Log.endSession(); 641 } 642 } 643 644 @Override 645 public void setCallerDisplayName(String callId, String callerDisplayName, int presentation, 646 Session.Info sessionInfo) { 647 Log.startSession(sessionInfo, "CSW.sCDN"); 648 long token = Binder.clearCallingIdentity(); 649 try { 650 synchronized (mLock) { 651 logIncoming("setCallerDisplayName %s %s %d", callId, callerDisplayName, 652 presentation); 653 Call call = mCallIdMapper.getCall(callId); 654 if (call != null) { 655 call.setCallerDisplayName(callerDisplayName, presentation); 656 } 657 } 658 } finally { 659 Binder.restoreCallingIdentity(token); 660 Log.endSession(); 661 } 662 } 663 664 @Override 665 public void setConferenceableConnections(String callId, List<String> conferenceableCallIds, 666 Session.Info sessionInfo) { 667 Log.startSession(sessionInfo, "CSW.sCC"); 668 long token = Binder.clearCallingIdentity(); 669 try { 670 synchronized (mLock) { 671 672 Call call = mCallIdMapper.getCall(callId); 673 if (call != null) { 674 logIncoming("setConferenceableConnections %s %s", callId, 675 conferenceableCallIds); 676 List<Call> conferenceableCalls = 677 new ArrayList<>(conferenceableCallIds.size()); 678 for (String otherId : conferenceableCallIds) { 679 Call otherCall = mCallIdMapper.getCall(otherId); 680 if (otherCall != null && otherCall != call) { 681 conferenceableCalls.add(otherCall); 682 } 683 } 684 call.setConferenceableCalls(conferenceableCalls); 685 } 686 } 687 } finally { 688 Binder.restoreCallingIdentity(token); 689 Log.endSession(); 690 } 691 } 692 693 @Override 694 public void addExistingConnection(String callId, ParcelableConnection connection, 695 Session.Info sessionInfo) { 696 Log.startSession(sessionInfo, "CSW.aEC"); 697 UserHandle userHandle = Binder.getCallingUserHandle(); 698 // Check that the Calling Package matches PhoneAccountHandle's Component Package 699 PhoneAccountHandle callingPhoneAccountHandle = connection.getPhoneAccount(); 700 if (callingPhoneAccountHandle != null) { 701 mAppOpsManager.checkPackage(Binder.getCallingUid(), 702 callingPhoneAccountHandle.getComponentName().getPackageName()); 703 } 704 long token = Binder.clearCallingIdentity(); 705 try { 706 synchronized (mLock) { 707 // Make sure that the PhoneAccount associated with the incoming 708 // ParcelableConnection is in fact registered to Telecom and is being called 709 // from the correct user. 710 List<PhoneAccountHandle> accountHandles = 711 mPhoneAccountRegistrar.getCallCapablePhoneAccounts(null /*uriScheme*/, 712 false /*includeDisabledAccounts*/, userHandle); 713 PhoneAccountHandle phoneAccountHandle = null; 714 for (PhoneAccountHandle accountHandle : accountHandles) { 715 if(accountHandle.equals(callingPhoneAccountHandle)) { 716 phoneAccountHandle = accountHandle; 717 } 718 } 719 // Allow the Sim call manager account as well, even if its disabled. 720 if (phoneAccountHandle == null && callingPhoneAccountHandle != null) { 721 if (callingPhoneAccountHandle.equals( 722 mPhoneAccountRegistrar.getSimCallManager(userHandle))) { 723 phoneAccountHandle = callingPhoneAccountHandle; 724 } 725 } 726 if (phoneAccountHandle != null) { 727 logIncoming("addExistingConnection %s %s", callId, connection); 728 729 Bundle connectionExtras = connection.getExtras(); 730 String connectIdToCheck = null; 731 if (connectionExtras != null && connectionExtras 732 .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) { 733 connectIdToCheck = connectionExtras 734 .getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID); 735 } else { 736 connectIdToCheck = callId; 737 } 738 // Check to see if this Connection has already been added. 739 Call alreadyAddedConnection = mCallsManager 740 .getAlreadyAddedConnection(connectIdToCheck); 741 742 if (alreadyAddedConnection != null 743 && mCallIdMapper.getCall(callId) == null) { 744 mCallIdMapper.addCall(alreadyAddedConnection, callId); 745 alreadyAddedConnection 746 .replaceConnectionService(ConnectionServiceWrapper.this); 747 return; 748 } 749 750 Call existingCall = mCallsManager 751 .createCallForExistingConnection(callId, connection); 752 mCallIdMapper.addCall(existingCall, callId); 753 existingCall.setConnectionService(ConnectionServiceWrapper.this); 754 } else { 755 Log.e(this, new RemoteException("The PhoneAccount being used is not " + 756 "currently registered with Telecom."), "Unable to " + 757 "addExistingConnection."); 758 } 759 } 760 } finally { 761 Binder.restoreCallingIdentity(token); 762 Log.endSession(); 763 } 764 } 765 766 @Override 767 public void onConnectionEvent(String callId, String event, Bundle extras, 768 Session.Info sessionInfo) { 769 Log.startSession(sessionInfo, "CSW.oCE"); 770 long token = Binder.clearCallingIdentity(); 771 try { 772 synchronized (mLock) { 773 Bundle.setDefusable(extras, true); 774 Call call = mCallIdMapper.getCall(callId); 775 if (call != null) { 776 call.onConnectionEvent(event, extras); 777 } 778 } 779 } finally { 780 Binder.restoreCallingIdentity(token); 781 Log.endSession(); 782 } 783 } 784 785 @Override 786 public void onRttInitiationSuccess(String callId, Session.Info sessionInfo) 787 throws RemoteException { 788 789 } 790 791 @Override 792 public void onRttInitiationFailure(String callId, int reason, Session.Info sessionInfo) 793 throws RemoteException { 794 Log.startSession(sessionInfo, "CSW.oRIF"); 795 long token = Binder.clearCallingIdentity(); 796 try { 797 synchronized (mLock) { 798 Call call = mCallIdMapper.getCall(callId); 799 if (call != null) { 800 call.onRttConnectionFailure(reason); 801 } 802 } 803 } finally { 804 Binder.restoreCallingIdentity(token); 805 Log.endSession(); 806 } 807 } 808 809 @Override 810 public void onRttSessionRemotelyTerminated(String callId, Session.Info sessionInfo) 811 throws RemoteException { 812 813 } 814 815 @Override 816 public void onRemoteRttRequest(String callId, Session.Info sessionInfo) 817 throws RemoteException { 818 Log.startSession(sessionInfo, "CSW.oRRR"); 819 long token = Binder.clearCallingIdentity(); 820 try { 821 synchronized (mLock) { 822 Call call = mCallIdMapper.getCall(callId); 823 if (call != null) { 824 call.onRemoteRttRequest(); 825 } 826 } 827 } finally { 828 Binder.restoreCallingIdentity(token); 829 Log.endSession(); 830 } 831 } 832 } 833 834 private final Adapter mAdapter = new Adapter(); 835 private final CallIdMapper mCallIdMapper = new CallIdMapper(Call::getConnectionId); 836 private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>(); 837 838 private Binder2 mBinder = new Binder2(); 839 private IConnectionService mServiceInterface; 840 private final ConnectionServiceRepository mConnectionServiceRepository; 841 private final PhoneAccountRegistrar mPhoneAccountRegistrar; 842 private final CallsManager mCallsManager; 843 private final AppOpsManager mAppOpsManager; 844 845 /** 846 * Creates a connection service. 847 * 848 * @param componentName The component name of the service with which to bind. 849 * @param connectionServiceRepository Connection service repository. 850 * @param phoneAccountRegistrar Phone account registrar 851 * @param callsManager Calls manager 852 * @param context The context. 853 * @param userHandle The {@link UserHandle} to use when binding. 854 */ 855 ConnectionServiceWrapper( 856 ComponentName componentName, 857 ConnectionServiceRepository connectionServiceRepository, 858 PhoneAccountRegistrar phoneAccountRegistrar, 859 CallsManager callsManager, 860 Context context, 861 TelecomSystem.SyncRoot lock, 862 UserHandle userHandle) { 863 super(ConnectionService.SERVICE_INTERFACE, componentName, context, lock, userHandle); 864 mConnectionServiceRepository = connectionServiceRepository; 865 phoneAccountRegistrar.addListener(new PhoneAccountRegistrar.Listener() { 866 // TODO -- Upon changes to PhoneAccountRegistrar, need to re-wire connections 867 // To do this, we must proxy remote ConnectionService objects 868 }); 869 mPhoneAccountRegistrar = phoneAccountRegistrar; 870 mCallsManager = callsManager; 871 mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 872 } 873 874 /** See {@link IConnectionService#addConnectionServiceAdapter}. */ 875 private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) { 876 if (isServiceValid("addConnectionServiceAdapter")) { 877 try { 878 logOutgoing("addConnectionServiceAdapter %s", adapter); 879 mServiceInterface.addConnectionServiceAdapter(adapter, Log.getExternalSession()); 880 } catch (RemoteException e) { 881 } 882 } 883 } 884 885 /** See {@link IConnectionService#removeConnectionServiceAdapter}. */ 886 private void removeConnectionServiceAdapter(IConnectionServiceAdapter adapter) { 887 if (isServiceValid("removeConnectionServiceAdapter")) { 888 try { 889 logOutgoing("removeConnectionServiceAdapter %s", adapter); 890 mServiceInterface.removeConnectionServiceAdapter(adapter, Log.getExternalSession()); 891 } catch (RemoteException e) { 892 } 893 } 894 } 895 896 /** 897 * Creates a new connection for a new outgoing call or to attach to an existing incoming call. 898 */ 899 @VisibleForTesting 900 public void createConnection(final Call call, final CreateConnectionResponse response) { 901 Log.d(this, "createConnection(%s) via %s.", call, getComponentName()); 902 BindCallback callback = new BindCallback() { 903 @Override 904 public void onSuccess() { 905 String callId = mCallIdMapper.getCallId(call); 906 mPendingResponses.put(callId, response); 907 908 GatewayInfo gatewayInfo = call.getGatewayInfo(); 909 Bundle extras = call.getIntentExtras(); 910 if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null && 911 gatewayInfo.getOriginalAddress() != null) { 912 extras = (Bundle) extras.clone(); 913 extras.putString( 914 TelecomManager.GATEWAY_PROVIDER_PACKAGE, 915 gatewayInfo.getGatewayProviderPackageName()); 916 extras.putParcelable( 917 TelecomManager.GATEWAY_ORIGINAL_ADDRESS, 918 gatewayInfo.getOriginalAddress()); 919 } 920 921 if (call.isIncoming() && mCallsManager.getEmergencyCallHelper() 922 .getLastEmergencyCallTimeMillis() > 0) { 923 // Add the last emergency call time to the connection request for incoming calls 924 if (extras == call.getIntentExtras()) { 925 extras = (Bundle) extras.clone(); 926 } 927 extras.putLong(android.telecom.Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 928 mCallsManager.getEmergencyCallHelper().getLastEmergencyCallTimeMillis()); 929 } 930 931 // Call is incoming and added because we're handing over from another; tell CS 932 // that its expected to handover. 933 if (call.isIncoming() && call.getHandoverSourceCall() != null) { 934 extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER, true); 935 extras.putParcelable(TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT, 936 call.getHandoverSourceCall().getTargetPhoneAccount()); 937 } 938 939 Log.addEvent(call, LogUtils.Events.START_CONNECTION, 940 Log.piiHandle(call.getHandle())); 941 942 ConnectionRequest connectionRequest = new ConnectionRequest.Builder() 943 .setAccountHandle(call.getTargetPhoneAccount()) 944 .setAddress(call.getHandle()) 945 .setExtras(extras) 946 .setVideoState(call.getVideoState()) 947 .setTelecomCallId(callId) 948 // For self-managed incoming calls, if there is another ongoing call Telecom 949 // is responsible for showing a UI to ask the user if they'd like to answer 950 // this new incoming call. 951 .setShouldShowIncomingCallUi( 952 !mCallsManager.shouldShowSystemIncomingCallUi(call)) 953 .setRttPipeFromInCall(call.getInCallToCsRttPipeForCs()) 954 .setRttPipeToInCall(call.getCsToInCallRttPipeForCs()) 955 .build(); 956 957 try { 958 mServiceInterface.createConnection( 959 call.getConnectionManagerPhoneAccount(), 960 callId, 961 connectionRequest, 962 call.shouldAttachToExistingConnection(), 963 call.isUnknown(), 964 Log.getExternalSession()); 965 966 } catch (RemoteException e) { 967 Log.e(this, e, "Failure to createConnection -- %s", getComponentName()); 968 mPendingResponses.remove(callId).handleCreateConnectionFailure( 969 new DisconnectCause(DisconnectCause.ERROR, e.toString())); 970 } 971 } 972 973 @Override 974 public void onFailure() { 975 Log.e(this, new Exception(), "Failure to call %s", getComponentName()); 976 response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.ERROR)); 977 } 978 }; 979 980 mBinder.bind(callback, call); 981 } 982 983 /** 984 * Notifies the {@link ConnectionService} associated with a {@link Call} that the request to 985 * create a connection has been denied or failed. 986 * @param call The call. 987 */ 988 void createConnectionFailed(final Call call) { 989 Log.d(this, "createConnectionFailed(%s) via %s.", call, getComponentName()); 990 BindCallback callback = new BindCallback() { 991 @Override 992 public void onSuccess() { 993 final String callId = mCallIdMapper.getCallId(call); 994 // If still bound, tell the connection service create connection has failed. 995 if (callId != null && isServiceValid("createConnectionFailed")) { 996 Log.addEvent(call, LogUtils.Events.CREATE_CONNECTION_FAILED, 997 Log.piiHandle(call.getHandle())); 998 try { 999 logOutgoing("createConnectionFailed %s", callId); 1000 mServiceInterface.createConnectionFailed( 1001 call.getConnectionManagerPhoneAccount(), 1002 callId, 1003 new ConnectionRequest( 1004 call.getTargetPhoneAccount(), 1005 call.getHandle(), 1006 call.getIntentExtras(), 1007 call.getVideoState(), 1008 callId, 1009 false), 1010 call.isIncoming(), 1011 Log.getExternalSession()); 1012 call.setDisconnectCause(new DisconnectCause(DisconnectCause.CANCELED)); 1013 call.disconnect(); 1014 } catch (RemoteException e) { 1015 } 1016 } 1017 } 1018 1019 @Override 1020 public void onFailure() { 1021 // Binding failed. Oh no. 1022 Log.w(this, "onFailure - could not bind to CS for call %s", call.getId()); 1023 } 1024 }; 1025 1026 mBinder.bind(callback, call); 1027 } 1028 1029 /** @see IConnectionService#abort(String, Session.Info) */ 1030 void abort(Call call) { 1031 // Clear out any pending outgoing call data 1032 final String callId = mCallIdMapper.getCallId(call); 1033 1034 // If still bound, tell the connection service to abort. 1035 if (callId != null && isServiceValid("abort")) { 1036 try { 1037 logOutgoing("abort %s", callId); 1038 mServiceInterface.abort(callId, Log.getExternalSession()); 1039 } catch (RemoteException e) { 1040 } 1041 } 1042 1043 removeCall(call, new DisconnectCause(DisconnectCause.LOCAL)); 1044 } 1045 1046 /** @see IConnectionService#silence(String, Session.Info) */ 1047 void silence(Call call) { 1048 final String callId = mCallIdMapper.getCallId(call); 1049 if (callId != null && isServiceValid("silence")) { 1050 try { 1051 logOutgoing("silence %s", callId); 1052 mServiceInterface.silence(callId, Log.getExternalSession()); 1053 } catch (RemoteException e) { 1054 } 1055 } 1056 } 1057 1058 /** @see IConnectionService#hold(String, Session.Info) */ 1059 void hold(Call call) { 1060 final String callId = mCallIdMapper.getCallId(call); 1061 if (callId != null && isServiceValid("hold")) { 1062 try { 1063 logOutgoing("hold %s", callId); 1064 mServiceInterface.hold(callId, Log.getExternalSession()); 1065 } catch (RemoteException e) { 1066 } 1067 } 1068 } 1069 1070 /** @see IConnectionService#unhold(String, Session.Info) */ 1071 void unhold(Call call) { 1072 final String callId = mCallIdMapper.getCallId(call); 1073 if (callId != null && isServiceValid("unhold")) { 1074 try { 1075 logOutgoing("unhold %s", callId); 1076 mServiceInterface.unhold(callId, Log.getExternalSession()); 1077 } catch (RemoteException e) { 1078 } 1079 } 1080 } 1081 1082 /** @see IConnectionService#onCallAudioStateChanged(String, CallAudioState, Session.Info) */ 1083 @VisibleForTesting 1084 public void onCallAudioStateChanged(Call activeCall, CallAudioState audioState) { 1085 final String callId = mCallIdMapper.getCallId(activeCall); 1086 if (callId != null && isServiceValid("onCallAudioStateChanged")) { 1087 try { 1088 logOutgoing("onCallAudioStateChanged %s %s", callId, audioState); 1089 mServiceInterface.onCallAudioStateChanged(callId, audioState, 1090 Log.getExternalSession()); 1091 } catch (RemoteException e) { 1092 } 1093 } 1094 } 1095 1096 /** @see IConnectionService#disconnect(String, Session.Info) */ 1097 void disconnect(Call call) { 1098 final String callId = mCallIdMapper.getCallId(call); 1099 if (callId != null && isServiceValid("disconnect")) { 1100 try { 1101 logOutgoing("disconnect %s", callId); 1102 mServiceInterface.disconnect(callId, Log.getExternalSession()); 1103 } catch (RemoteException e) { 1104 } 1105 } 1106 } 1107 1108 /** @see IConnectionService#answer(String, Session.Info) */ 1109 void answer(Call call, int videoState) { 1110 final String callId = mCallIdMapper.getCallId(call); 1111 if (callId != null && isServiceValid("answer")) { 1112 try { 1113 logOutgoing("answer %s %d", callId, videoState); 1114 if (VideoProfile.isAudioOnly(videoState)) { 1115 mServiceInterface.answer(callId, Log.getExternalSession()); 1116 } else { 1117 mServiceInterface.answerVideo(callId, videoState, Log.getExternalSession()); 1118 } 1119 } catch (RemoteException e) { 1120 } 1121 } 1122 } 1123 1124 /** @see IConnectionService#reject(String, Session.Info) */ 1125 void reject(Call call, boolean rejectWithMessage, String message) { 1126 final String callId = mCallIdMapper.getCallId(call); 1127 if (callId != null && isServiceValid("reject")) { 1128 try { 1129 logOutgoing("reject %s", callId); 1130 1131 if (rejectWithMessage && call.can( 1132 Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) { 1133 mServiceInterface.rejectWithMessage(callId, message, Log.getExternalSession()); 1134 } else { 1135 mServiceInterface.reject(callId, Log.getExternalSession()); 1136 } 1137 } catch (RemoteException e) { 1138 } 1139 } 1140 } 1141 1142 /** @see IConnectionService#playDtmfTone(String, char, Session.Info) */ 1143 void playDtmfTone(Call call, char digit) { 1144 final String callId = mCallIdMapper.getCallId(call); 1145 if (callId != null && isServiceValid("playDtmfTone")) { 1146 try { 1147 logOutgoing("playDtmfTone %s %c", callId, digit); 1148 mServiceInterface.playDtmfTone(callId, digit, Log.getExternalSession()); 1149 } catch (RemoteException e) { 1150 } 1151 } 1152 } 1153 1154 /** @see IConnectionService#stopDtmfTone(String, Session.Info) */ 1155 void stopDtmfTone(Call call) { 1156 final String callId = mCallIdMapper.getCallId(call); 1157 if (callId != null && isServiceValid("stopDtmfTone")) { 1158 try { 1159 logOutgoing("stopDtmfTone %s", callId); 1160 mServiceInterface.stopDtmfTone(callId, Log.getExternalSession()); 1161 } catch (RemoteException e) { 1162 } 1163 } 1164 } 1165 1166 void addCall(Call call) { 1167 if (mCallIdMapper.getCallId(call) == null) { 1168 mCallIdMapper.addCall(call); 1169 } 1170 } 1171 1172 /** 1173 * Associates newCall with this connection service by replacing callToReplace. 1174 */ 1175 void replaceCall(Call newCall, Call callToReplace) { 1176 Preconditions.checkState(callToReplace.getConnectionService() == this); 1177 mCallIdMapper.replaceCall(newCall, callToReplace); 1178 } 1179 1180 void removeCall(Call call) { 1181 removeCall(call, new DisconnectCause(DisconnectCause.ERROR)); 1182 } 1183 1184 void removeCall(String callId, DisconnectCause disconnectCause) { 1185 CreateConnectionResponse response = mPendingResponses.remove(callId); 1186 if (response != null) { 1187 response.handleCreateConnectionFailure(disconnectCause); 1188 } 1189 1190 mCallIdMapper.removeCall(callId); 1191 } 1192 1193 void removeCall(Call call, DisconnectCause disconnectCause) { 1194 CreateConnectionResponse response = mPendingResponses.remove(mCallIdMapper.getCallId(call)); 1195 if (response != null) { 1196 response.handleCreateConnectionFailure(disconnectCause); 1197 } 1198 1199 mCallIdMapper.removeCall(call); 1200 } 1201 1202 void onPostDialContinue(Call call, boolean proceed) { 1203 final String callId = mCallIdMapper.getCallId(call); 1204 if (callId != null && isServiceValid("onPostDialContinue")) { 1205 try { 1206 logOutgoing("onPostDialContinue %s %b", callId, proceed); 1207 mServiceInterface.onPostDialContinue(callId, proceed, Log.getExternalSession()); 1208 } catch (RemoteException ignored) { 1209 } 1210 } 1211 } 1212 1213 void conference(final Call call, Call otherCall) { 1214 final String callId = mCallIdMapper.getCallId(call); 1215 final String otherCallId = mCallIdMapper.getCallId(otherCall); 1216 if (callId != null && otherCallId != null && isServiceValid("conference")) { 1217 try { 1218 logOutgoing("conference %s %s", callId, otherCallId); 1219 mServiceInterface.conference(callId, otherCallId, Log.getExternalSession()); 1220 } catch (RemoteException ignored) { 1221 } 1222 } 1223 } 1224 1225 void splitFromConference(Call call) { 1226 final String callId = mCallIdMapper.getCallId(call); 1227 if (callId != null && isServiceValid("splitFromConference")) { 1228 try { 1229 logOutgoing("splitFromConference %s", callId); 1230 mServiceInterface.splitFromConference(callId, Log.getExternalSession()); 1231 } catch (RemoteException ignored) { 1232 } 1233 } 1234 } 1235 1236 void mergeConference(Call call) { 1237 final String callId = mCallIdMapper.getCallId(call); 1238 if (callId != null && isServiceValid("mergeConference")) { 1239 try { 1240 logOutgoing("mergeConference %s", callId); 1241 mServiceInterface.mergeConference(callId, Log.getExternalSession()); 1242 } catch (RemoteException ignored) { 1243 } 1244 } 1245 } 1246 1247 void swapConference(Call call) { 1248 final String callId = mCallIdMapper.getCallId(call); 1249 if (callId != null && isServiceValid("swapConference")) { 1250 try { 1251 logOutgoing("swapConference %s", callId); 1252 mServiceInterface.swapConference(callId, Log.getExternalSession()); 1253 } catch (RemoteException ignored) { 1254 } 1255 } 1256 } 1257 1258 void pullExternalCall(Call call) { 1259 final String callId = mCallIdMapper.getCallId(call); 1260 if (callId != null && isServiceValid("pullExternalCall")) { 1261 try { 1262 logOutgoing("pullExternalCall %s", callId); 1263 mServiceInterface.pullExternalCall(callId, Log.getExternalSession()); 1264 } catch (RemoteException ignored) { 1265 } 1266 } 1267 } 1268 1269 void sendCallEvent(Call call, String event, Bundle extras) { 1270 final String callId = mCallIdMapper.getCallId(call); 1271 if (callId != null && isServiceValid("sendCallEvent")) { 1272 try { 1273 logOutgoing("sendCallEvent %s %s", callId, event); 1274 mServiceInterface.sendCallEvent(callId, event, extras, Log.getExternalSession()); 1275 } catch (RemoteException ignored) { 1276 } 1277 } 1278 } 1279 1280 void onExtrasChanged(Call call, Bundle extras) { 1281 final String callId = mCallIdMapper.getCallId(call); 1282 if (callId != null && isServiceValid("onExtrasChanged")) { 1283 try { 1284 logOutgoing("onExtrasChanged %s %s", callId, extras); 1285 mServiceInterface.onExtrasChanged(callId, extras, Log.getExternalSession()); 1286 } catch (RemoteException ignored) { 1287 } 1288 } 1289 } 1290 1291 void startRtt(Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall) { 1292 final String callId = mCallIdMapper.getCallId(call); 1293 if (callId != null && isServiceValid("startRtt")) { 1294 try { 1295 logOutgoing("startRtt: %s %s %s", callId, fromInCall, toInCall); 1296 mServiceInterface.startRtt(callId, fromInCall, toInCall, Log.getExternalSession()); 1297 } catch (RemoteException ignored) { 1298 } 1299 } 1300 } 1301 1302 void stopRtt(Call call) { 1303 final String callId = mCallIdMapper.getCallId(call); 1304 if (callId != null && isServiceValid("stopRtt")) { 1305 try { 1306 logOutgoing("stopRtt: %s", callId); 1307 mServiceInterface.stopRtt(callId, Log.getExternalSession()); 1308 } catch (RemoteException ignored) { 1309 } 1310 } 1311 } 1312 1313 void respondToRttRequest( 1314 Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall) { 1315 final String callId = mCallIdMapper.getCallId(call); 1316 if (callId != null && isServiceValid("respondToRttRequest")) { 1317 try { 1318 logOutgoing("respondToRttRequest: %s %s %s", callId, fromInCall, toInCall); 1319 mServiceInterface.respondToRttUpgradeRequest( 1320 callId, fromInCall, toInCall, Log.getExternalSession()); 1321 } catch (RemoteException ignored) { 1322 } 1323 } 1324 } 1325 1326 /** {@inheritDoc} */ 1327 @Override 1328 protected void setServiceInterface(IBinder binder) { 1329 mServiceInterface = IConnectionService.Stub.asInterface(binder); 1330 Log.v(this, "Adding Connection Service Adapter."); 1331 addConnectionServiceAdapter(mAdapter); 1332 } 1333 1334 /** {@inheritDoc} */ 1335 @Override 1336 protected void removeServiceInterface() { 1337 Log.v(this, "Removing Connection Service Adapter."); 1338 removeConnectionServiceAdapter(mAdapter); 1339 // We have lost our service connection. Notify the world that this service is done. 1340 // We must notify the adapter before CallsManager. The adapter will force any pending 1341 // outgoing calls to try the next service. This needs to happen before CallsManager 1342 // tries to clean up any calls still associated with this service. 1343 handleConnectionServiceDeath(); 1344 mCallsManager.handleConnectionServiceDeath(this); 1345 mServiceInterface = null; 1346 } 1347 1348 private void handleCreateConnectionComplete( 1349 String callId, 1350 ConnectionRequest request, 1351 ParcelableConnection connection) { 1352 // TODO: Note we are not using parameter "request", which is a side effect of our tacit 1353 // assumption that we have at most one outgoing connection attempt per ConnectionService. 1354 // This may not continue to be the case. 1355 if (connection.getState() == Connection.STATE_DISCONNECTED) { 1356 // A connection that begins in the DISCONNECTED state is an indication of 1357 // failure to connect; we handle all failures uniformly 1358 removeCall(callId, connection.getDisconnectCause()); 1359 } else { 1360 // Successful connection 1361 if (mPendingResponses.containsKey(callId)) { 1362 mPendingResponses.remove(callId) 1363 .handleCreateConnectionSuccess(mCallIdMapper, connection); 1364 } 1365 } 1366 } 1367 1368 /** 1369 * Called when the associated connection service dies. 1370 */ 1371 private void handleConnectionServiceDeath() { 1372 if (!mPendingResponses.isEmpty()) { 1373 CreateConnectionResponse[] responses = mPendingResponses.values().toArray( 1374 new CreateConnectionResponse[mPendingResponses.values().size()]); 1375 mPendingResponses.clear(); 1376 for (int i = 0; i < responses.length; i++) { 1377 responses[i].handleCreateConnectionFailure( 1378 new DisconnectCause(DisconnectCause.ERROR, "CS_DEATH")); 1379 } 1380 } 1381 mCallIdMapper.clear(); 1382 } 1383 1384 private void logIncoming(String msg, Object... params) { 1385 Log.d(this, "ConnectionService -> Telecom[" + mComponentName.flattenToShortString() + "]: " 1386 + msg, params); 1387 } 1388 1389 private void logOutgoing(String msg, Object... params) { 1390 Log.d(this, "Telecom -> ConnectionService[" + mComponentName.flattenToShortString() + "]: " 1391 + msg, params); 1392 } 1393 1394 private void queryRemoteConnectionServices(final UserHandle userHandle, 1395 final RemoteServiceCallback callback) { 1396 // Only give remote connection services to this connection service if it is listed as 1397 // the connection manager. 1398 PhoneAccountHandle simCallManager = mPhoneAccountRegistrar.getSimCallManager(userHandle); 1399 Log.d(this, "queryRemoteConnectionServices finds simCallManager = %s", simCallManager); 1400 if (simCallManager == null || 1401 !simCallManager.getComponentName().equals(getComponentName())) { 1402 noRemoteServices(callback); 1403 return; 1404 } 1405 1406 // Make a list of ConnectionServices that are listed as being associated with SIM accounts 1407 final Set<ConnectionServiceWrapper> simServices = Collections.newSetFromMap( 1408 new ConcurrentHashMap<ConnectionServiceWrapper, Boolean>(8, 0.9f, 1)); 1409 for (PhoneAccountHandle handle : mPhoneAccountRegistrar.getSimPhoneAccounts(userHandle)) { 1410 ConnectionServiceWrapper service = mConnectionServiceRepository.getService( 1411 handle.getComponentName(), handle.getUserHandle()); 1412 if (service != null) { 1413 simServices.add(service); 1414 } 1415 } 1416 1417 final List<ComponentName> simServiceComponentNames = new ArrayList<>(); 1418 final List<IBinder> simServiceBinders = new ArrayList<>(); 1419 1420 Log.v(this, "queryRemoteConnectionServices, simServices = %s", simServices); 1421 1422 for (ConnectionServiceWrapper simService : simServices) { 1423 if (simService == this) { 1424 // Only happens in the unlikely case that a SIM service is also a SIM call manager 1425 continue; 1426 } 1427 1428 final ConnectionServiceWrapper currentSimService = simService; 1429 1430 currentSimService.mBinder.bind(new BindCallback() { 1431 @Override 1432 public void onSuccess() { 1433 Log.d(this, "Adding simService %s", currentSimService.getComponentName()); 1434 simServiceComponentNames.add(currentSimService.getComponentName()); 1435 simServiceBinders.add(currentSimService.mServiceInterface.asBinder()); 1436 maybeComplete(); 1437 } 1438 1439 @Override 1440 public void onFailure() { 1441 Log.d(this, "Failed simService %s", currentSimService.getComponentName()); 1442 // We know maybeComplete() will always be a no-op from now on, so go ahead and 1443 // signal failure of the entire request 1444 noRemoteServices(callback); 1445 } 1446 1447 private void maybeComplete() { 1448 if (simServiceComponentNames.size() == simServices.size()) { 1449 setRemoteServices(callback, simServiceComponentNames, simServiceBinders); 1450 } 1451 } 1452 }, null); 1453 } 1454 } 1455 1456 private void setRemoteServices( 1457 RemoteServiceCallback callback, 1458 List<ComponentName> componentNames, 1459 List<IBinder> binders) { 1460 try { 1461 callback.onResult(componentNames, binders); 1462 } catch (RemoteException e) { 1463 Log.e(this, e, "Contacting ConnectionService %s", 1464 ConnectionServiceWrapper.this.getComponentName()); 1465 } 1466 } 1467 1468 private void noRemoteServices(RemoteServiceCallback callback) { 1469 setRemoteServices(callback, Collections.EMPTY_LIST, Collections.EMPTY_LIST); 1470 } 1471 } 1472