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