1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.telecom; 18 19 import android.net.Uri; 20 import android.os.Binder; 21 import android.os.Bundle; 22 import android.telecom.Log; 23 import android.telecom.PhoneAccountHandle; 24 25 import com.android.internal.telecom.IInCallAdapter; 26 27 import java.util.List; 28 29 /** 30 * Receives call commands and updates from in-call app and passes them through to CallsManager. 31 * {@link InCallController} creates an instance of this class and passes it to the in-call app after 32 * binding to it. This adapter can receive commands and updates until the in-call app is unbound. 33 */ 34 class InCallAdapter extends IInCallAdapter.Stub { 35 private final CallsManager mCallsManager; 36 private final CallIdMapper mCallIdMapper; 37 private final TelecomSystem.SyncRoot mLock; 38 private final String mOwnerPackageName; 39 40 /** Persists the specified parameters. */ InCallAdapter(CallsManager callsManager, CallIdMapper callIdMapper, TelecomSystem.SyncRoot lock, String ownerPackageName)41 public InCallAdapter(CallsManager callsManager, CallIdMapper callIdMapper, 42 TelecomSystem.SyncRoot lock, String ownerPackageName) { 43 mCallsManager = callsManager; 44 mCallIdMapper = callIdMapper; 45 mLock = lock; 46 mOwnerPackageName = ownerPackageName; 47 } 48 49 @Override answerCall(String callId, int videoState)50 public void answerCall(String callId, int videoState) { 51 try { 52 Log.startSession(LogUtils.Sessions.ICA_ANSWER_CALL, mOwnerPackageName); 53 long token = Binder.clearCallingIdentity(); 54 try { 55 synchronized (mLock) { 56 Log.d(this, "answerCall(%s,%d)", callId, videoState); 57 Call call = mCallIdMapper.getCall(callId); 58 if (call != null) { 59 mCallsManager.answerCall(call, videoState); 60 } else { 61 Log.w(this, "answerCall, unknown call id: %s", callId); 62 } 63 } 64 } finally { 65 Binder.restoreCallingIdentity(token); 66 } 67 } finally { 68 Log.endSession(); 69 } 70 } 71 72 @Override deflectCall(String callId, Uri address)73 public void deflectCall(String callId, Uri address) { 74 try { 75 Log.startSession(LogUtils.Sessions.ICA_DEFLECT_CALL, mOwnerPackageName); 76 long token = Binder.clearCallingIdentity(); 77 try { 78 synchronized (mLock) { 79 Log.i(this, "deflectCall - %s, %s ", callId, Log.pii(address)); 80 Call call = mCallIdMapper.getCall(callId); 81 if (call != null) { 82 mCallsManager.deflectCall(call, address); 83 } else { 84 Log.w(this, "deflectCall, unknown call id: %s", callId); 85 } 86 } 87 } finally { 88 Binder.restoreCallingIdentity(token); 89 } 90 } finally { 91 Log.endSession(); 92 } 93 } 94 95 @Override rejectCall(String callId, boolean rejectWithMessage, String textMessage)96 public void rejectCall(String callId, boolean rejectWithMessage, String textMessage) { 97 try { 98 Log.startSession(LogUtils.Sessions.ICA_REJECT_CALL, mOwnerPackageName); 99 100 int callingUid = Binder.getCallingUid(); 101 long token = Binder.clearCallingIdentity(); 102 try { 103 synchronized (mLock) { 104 // Check to make sure the in-call app's user isn't restricted from sending SMS. 105 // If so, silently drop the outgoing message. Also drop message if the screen is 106 // locked. 107 if (!mCallsManager.isReplyWithSmsAllowed(callingUid)) { 108 rejectWithMessage = false; 109 textMessage = null; 110 } 111 112 Log.d(this, "rejectCall(%s,%b,%s)", callId, rejectWithMessage, textMessage); 113 Call call = mCallIdMapper.getCall(callId); 114 if (call != null) { 115 mCallsManager.rejectCall(call, rejectWithMessage, textMessage); 116 } else { 117 Log.w(this, "setRingback, unknown call id: %s", callId); 118 } 119 } 120 } finally { 121 Binder.restoreCallingIdentity(token); 122 } 123 } finally { 124 Log.endSession(); 125 } 126 } 127 128 @Override rejectCallWithReason(String callId, @android.telecom.Call.RejectReason int rejectReason)129 public void rejectCallWithReason(String callId, 130 @android.telecom.Call.RejectReason int rejectReason) { 131 try { 132 Log.startSession(LogUtils.Sessions.ICA_REJECT_CALL, mOwnerPackageName); 133 134 int callingUid = Binder.getCallingUid(); 135 long token = Binder.clearCallingIdentity(); 136 try { 137 synchronized (mLock) { 138 Log.d(this, "rejectCallWithReason(%s,%d)", callId, rejectReason); 139 Call call = mCallIdMapper.getCall(callId); 140 if (call != null) { 141 mCallsManager.rejectCall(call, rejectReason); 142 } else { 143 Log.w(this, "rejectCallWithReason, unknown call id: %s", callId); 144 } 145 } 146 } finally { 147 Binder.restoreCallingIdentity(token); 148 } 149 } finally { 150 Log.endSession(); 151 } 152 } 153 transferCall(String callId, Uri targetNumber, boolean isConfirmationRequired)154 public void transferCall(String callId, Uri targetNumber, boolean isConfirmationRequired) { 155 try { 156 Log.startSession(LogUtils.Sessions.ICA_TRANSFER_CALL, mOwnerPackageName); 157 long token = Binder.clearCallingIdentity(); 158 try { 159 synchronized (mLock) { 160 Log.i(this, "transferCall - %s, %s, %b", callId, Log.pii(targetNumber), 161 isConfirmationRequired); 162 Call call = mCallIdMapper.getCall(callId); 163 if (call != null) { 164 mCallsManager.transferCall(call, targetNumber, isConfirmationRequired); 165 } else { 166 Log.w(this, "transferCall, unknown call id: %s", callId); 167 } 168 } 169 } finally { 170 Binder.restoreCallingIdentity(token); 171 } 172 } finally { 173 Log.endSession(); 174 } 175 } 176 177 @Override consultativeTransfer(String callId, String otherCallId)178 public void consultativeTransfer(String callId, String otherCallId) { 179 try { 180 Log.startSession(LogUtils.Sessions.ICA_CONSULTATIVE_TRANSFER, mOwnerPackageName); 181 long token = Binder.clearCallingIdentity(); 182 try { 183 synchronized (mLock) { 184 Log.i(this, "consultativeTransfer - %s, %s", callId, otherCallId); 185 Call call = mCallIdMapper.getCall(callId); 186 Call otherCall = mCallIdMapper.getCall(otherCallId); 187 if (call != null && otherCall != null) { 188 mCallsManager.transferCall(call, otherCall); 189 } else { 190 Log.w(this, "consultativeTransfer, unknown call id: %s or %s", 191 callId, otherCallId); 192 } 193 } 194 } finally { 195 Binder.restoreCallingIdentity(token); 196 } 197 } finally { 198 Log.endSession(); 199 } 200 } 201 202 @Override playDtmfTone(String callId, char digit)203 public void playDtmfTone(String callId, char digit) { 204 try { 205 Log.startSession("ICA.pDT", mOwnerPackageName); 206 long token = Binder.clearCallingIdentity(); 207 try { 208 synchronized (mLock) { 209 Log.d(this, "playDtmfTone(%s,%c)", callId, digit); 210 Call call = mCallIdMapper.getCall(callId); 211 if (call != null) { 212 mCallsManager.playDtmfTone(call, digit); 213 } else { 214 Log.w(this, "playDtmfTone, unknown call id: %s", callId); 215 } 216 } 217 } finally { 218 Binder.restoreCallingIdentity(token); 219 } 220 } finally { 221 Log.endSession(); 222 } 223 } 224 225 @Override stopDtmfTone(String callId)226 public void stopDtmfTone(String callId) { 227 try { 228 Log.startSession("ICA.sDT", mOwnerPackageName); 229 long token = Binder.clearCallingIdentity(); 230 try { 231 synchronized (mLock) { 232 Log.d(this, "stopDtmfTone(%s)", callId); 233 Call call = mCallIdMapper.getCall(callId); 234 if (call != null) { 235 mCallsManager.stopDtmfTone(call); 236 } else { 237 Log.w(this, "stopDtmfTone, unknown call id: %s", callId); 238 } 239 } 240 } finally { 241 Binder.restoreCallingIdentity(token); 242 } 243 } finally { 244 Log.endSession(); 245 } 246 } 247 248 @Override postDialContinue(String callId, boolean proceed)249 public void postDialContinue(String callId, boolean proceed) { 250 try { 251 Log.startSession("ICA.pDC", mOwnerPackageName); 252 long token = Binder.clearCallingIdentity(); 253 try { 254 synchronized (mLock) { 255 Log.d(this, "postDialContinue(%s)", callId); 256 Call call = mCallIdMapper.getCall(callId); 257 if (call != null) { 258 mCallsManager.postDialContinue(call, proceed); 259 } else { 260 Log.w(this, "postDialContinue, unknown call id: %s", callId); 261 } 262 } 263 } finally { 264 Binder.restoreCallingIdentity(token); 265 } 266 } finally { 267 Log.endSession(); 268 } 269 } 270 271 @Override disconnectCall(String callId)272 public void disconnectCall(String callId) { 273 try { 274 Log.startSession(LogUtils.Sessions.ICA_DISCONNECT_CALL, mOwnerPackageName); 275 long token = Binder.clearCallingIdentity(); 276 try { 277 synchronized (mLock) { 278 Log.v(this, "disconnectCall: %s", callId); 279 Call call = mCallIdMapper.getCall(callId); 280 if (call != null) { 281 mCallsManager.disconnectCall(call); 282 } else { 283 Log.w(this, "disconnectCall, unknown call id: %s", callId); 284 } 285 } 286 } finally { 287 Binder.restoreCallingIdentity(token); 288 } 289 } finally { 290 Log.endSession(); 291 } 292 } 293 294 @Override holdCall(String callId)295 public void holdCall(String callId) { 296 try { 297 Log.startSession(LogUtils.Sessions.ICA_HOLD_CALL, mOwnerPackageName); 298 long token = Binder.clearCallingIdentity(); 299 try { 300 synchronized (mLock) { 301 Call call = mCallIdMapper.getCall(callId); 302 if (call != null) { 303 mCallsManager.holdCall(call); 304 } else { 305 Log.w(this, "holdCall, unknown call id: %s", callId); 306 } 307 } 308 } finally { 309 Binder.restoreCallingIdentity(token); 310 } 311 } finally { 312 Log.endSession(); 313 } 314 } 315 316 @Override unholdCall(String callId)317 public void unholdCall(String callId) { 318 try { 319 Log.startSession(LogUtils.Sessions.ICA_UNHOLD_CALL, mOwnerPackageName); 320 long token = Binder.clearCallingIdentity(); 321 try { 322 synchronized (mLock) { 323 Call call = mCallIdMapper.getCall(callId); 324 if (call != null) { 325 mCallsManager.unholdCall(call); 326 } else { 327 Log.w(this, "unholdCall, unknown call id: %s", callId); 328 } 329 } 330 } finally { 331 Binder.restoreCallingIdentity(token); 332 } 333 } finally { 334 Log.endSession(); 335 } 336 } 337 338 @Override phoneAccountSelected(String callId, PhoneAccountHandle accountHandle, boolean setDefault)339 public void phoneAccountSelected(String callId, PhoneAccountHandle accountHandle, 340 boolean setDefault) { 341 try { 342 Log.startSession("ICA.pAS", mOwnerPackageName); 343 long token = Binder.clearCallingIdentity(); 344 try { 345 synchronized (mLock) { 346 Call call = mCallIdMapper.getCall(callId); 347 if (call != null) { 348 mCallsManager.phoneAccountSelected(call, accountHandle, setDefault); 349 } else { 350 Log.w(this, "phoneAccountSelected, unknown call id: %s", callId); 351 } 352 } 353 } finally { 354 Binder.restoreCallingIdentity(token); 355 } 356 } finally { 357 Log.endSession(); 358 } 359 } 360 361 @Override mute(boolean shouldMute)362 public void mute(boolean shouldMute) { 363 try { 364 Log.startSession(LogUtils.Sessions.ICA_MUTE, mOwnerPackageName); 365 long token = Binder.clearCallingIdentity(); 366 try { 367 synchronized (mLock) { 368 mCallsManager.mute(shouldMute); 369 } 370 } finally { 371 Binder.restoreCallingIdentity(token); 372 } 373 } finally { 374 Log.endSession(); 375 } 376 } 377 378 @Override setAudioRoute(int route, String bluetoothAddress)379 public void setAudioRoute(int route, String bluetoothAddress) { 380 try { 381 Log.startSession(LogUtils.Sessions.ICA_SET_AUDIO_ROUTE, mOwnerPackageName); 382 long token = Binder.clearCallingIdentity(); 383 try { 384 synchronized (mLock) { 385 mCallsManager.setAudioRoute(route, bluetoothAddress); 386 } 387 } finally { 388 Binder.restoreCallingIdentity(token); 389 } 390 } finally { 391 Log.endSession(); 392 } 393 } 394 395 @Override enterBackgroundAudioProcessing(String callId)396 public void enterBackgroundAudioProcessing(String callId) { 397 try { 398 Log.startSession(LogUtils.Sessions.ICA_ENTER_AUDIO_PROCESSING, mOwnerPackageName); 399 // TODO: enforce the extra permission. 400 Binder.withCleanCallingIdentity(() -> { 401 synchronized (mLock) { 402 Call call = mCallIdMapper.getCall(callId); 403 if (call != null) { 404 mCallsManager.enterBackgroundAudioProcessing(call, mOwnerPackageName); 405 } else { 406 Log.w(this, "enterBackgroundAudioProcessing, unknown call id: %s", callId); 407 } 408 } 409 }); 410 } finally { 411 Log.endSession(); 412 } 413 } 414 415 @Override exitBackgroundAudioProcessing(String callId, boolean shouldRing)416 public void exitBackgroundAudioProcessing(String callId, boolean shouldRing) { 417 try { 418 Log.startSession(LogUtils.Sessions.ICA_EXIT_AUDIO_PROCESSING, mOwnerPackageName); 419 Binder.withCleanCallingIdentity(() -> { 420 synchronized (mLock) { 421 Call call = mCallIdMapper.getCall(callId); 422 if (call != null) { 423 mCallsManager.exitBackgroundAudioProcessing(call, shouldRing); 424 } else { 425 Log.w(InCallAdapter.this, 426 "exitBackgroundAudioProcessing, unknown call id: %s", callId); 427 } 428 } 429 }); 430 } finally { 431 Log.endSession(); 432 } 433 } 434 435 @Override conference(String callId, String otherCallId)436 public void conference(String callId, String otherCallId) { 437 try { 438 Log.startSession(LogUtils.Sessions.ICA_CONFERENCE, mOwnerPackageName); 439 long token = Binder.clearCallingIdentity(); 440 try { 441 synchronized (mLock) { 442 Call call = mCallIdMapper.getCall(callId); 443 Call otherCall = mCallIdMapper.getCall(otherCallId); 444 if (call != null && otherCall != null) { 445 mCallsManager.conference(call, otherCall); 446 } else { 447 Log.w(this, "conference, unknown call id: %s or %s", callId, otherCallId); 448 } 449 } 450 } finally { 451 Binder.restoreCallingIdentity(token); 452 } 453 } finally { 454 Log.endSession(); 455 } 456 } 457 458 @Override splitFromConference(String callId)459 public void splitFromConference(String callId) { 460 try { 461 Log.startSession("ICA.sFC", mOwnerPackageName); 462 long token = Binder.clearCallingIdentity(); 463 try { 464 synchronized (mLock) { 465 Call call = mCallIdMapper.getCall(callId); 466 if (call != null) { 467 call.splitFromConference(); 468 } else { 469 Log.w(this, "splitFromConference, unknown call id: %s", callId); 470 } 471 } 472 } finally { 473 Binder.restoreCallingIdentity(token); 474 } 475 } finally { 476 Log.endSession(); 477 } 478 } 479 480 @Override mergeConference(String callId)481 public void mergeConference(String callId) { 482 try { 483 Log.startSession("ICA.mC", mOwnerPackageName); 484 long token = Binder.clearCallingIdentity(); 485 try { 486 synchronized (mLock) { 487 Call call = mCallIdMapper.getCall(callId); 488 if (call != null) { 489 call.mergeConference(); 490 } else { 491 Log.w(this, "mergeConference, unknown call id: %s", callId); 492 } 493 } 494 } finally { 495 Binder.restoreCallingIdentity(token); 496 } 497 } finally { 498 Log.endSession(); 499 } 500 } 501 502 @Override swapConference(String callId)503 public void swapConference(String callId) { 504 try { 505 Log.startSession("ICA.sC", mOwnerPackageName); 506 long token = Binder.clearCallingIdentity(); 507 try { 508 synchronized (mLock) { 509 Call call = mCallIdMapper.getCall(callId); 510 if (call != null) { 511 call.swapConference(); 512 } else { 513 Log.w(this, "swapConference, unknown call id: %s", callId); 514 } 515 } 516 } finally { 517 Binder.restoreCallingIdentity(token); 518 } 519 } finally { 520 Log.endSession(); 521 } 522 } 523 524 @Override addConferenceParticipants(String callId, List<Uri> participants)525 public void addConferenceParticipants(String callId, List<Uri> participants) { 526 try { 527 Log.startSession("ICA.aCP", mOwnerPackageName); 528 long token = Binder.clearCallingIdentity(); 529 try { 530 synchronized (mLock) { 531 Call call = mCallIdMapper.getCall(callId); 532 if (call != null) { 533 call.addConferenceParticipants(participants); 534 } else { 535 Log.w(this, "addConferenceParticipants, unknown call id: %s", callId); 536 } 537 } 538 } finally { 539 Binder.restoreCallingIdentity(token); 540 } 541 } finally { 542 Log.endSession(); 543 } 544 } 545 546 547 @Override pullExternalCall(String callId)548 public void pullExternalCall(String callId) { 549 try { 550 Log.startSession("ICA.pEC", mOwnerPackageName); 551 long token = Binder.clearCallingIdentity(); 552 try { 553 synchronized (mLock) { 554 Call call = mCallIdMapper.getCall(callId); 555 if (call != null) { 556 call.pullExternalCall(); 557 } else { 558 Log.w(this, "pullExternalCall, unknown call id: %s", callId); 559 } 560 } 561 } finally { 562 Binder.restoreCallingIdentity(token); 563 } 564 } finally { 565 Log.endSession(); 566 } 567 } 568 569 @Override sendCallEvent(String callId, String event, int targetSdkVer, Bundle extras)570 public void sendCallEvent(String callId, String event, int targetSdkVer, Bundle extras) { 571 try { 572 Log.startSession("ICA.sCE", mOwnerPackageName); 573 long token = Binder.clearCallingIdentity(); 574 try { 575 synchronized (mLock) { 576 Call call = mCallIdMapper.getCall(callId); 577 if (call != null) { 578 call.sendCallEvent(event, targetSdkVer, extras); 579 } else { 580 Log.w(this, "sendCallEvent, unknown call id: %s", callId); 581 } 582 } 583 } finally { 584 Binder.restoreCallingIdentity(token); 585 } 586 } finally { 587 Log.endSession(); 588 } 589 } 590 591 @Override putExtras(String callId, Bundle extras)592 public void putExtras(String callId, Bundle extras) { 593 try { 594 Log.startSession("ICA.pE", mOwnerPackageName); 595 long token = Binder.clearCallingIdentity(); 596 try { 597 synchronized (mLock) { 598 Call call = mCallIdMapper.getCall(callId); 599 if (call != null) { 600 call.putExtras(Call.SOURCE_INCALL_SERVICE, extras); 601 } else { 602 Log.w(this, "putExtras, unknown call id: %s", callId); 603 } 604 } 605 } finally { 606 Binder.restoreCallingIdentity(token); 607 } 608 } finally { 609 Log.endSession(); 610 } 611 } 612 613 @Override removeExtras(String callId, List<String> keys)614 public void removeExtras(String callId, List<String> keys) { 615 try { 616 Log.startSession("ICA.rE", mOwnerPackageName); 617 long token = Binder.clearCallingIdentity(); 618 try { 619 synchronized (mLock) { 620 Call call = mCallIdMapper.getCall(callId); 621 if (call != null) { 622 call.removeExtras(Call.SOURCE_INCALL_SERVICE, keys); 623 } else { 624 Log.w(this, "removeExtra, unknown call id: %s", callId); 625 } 626 } 627 } finally { 628 Binder.restoreCallingIdentity(token); 629 } 630 } finally { 631 Log.endSession(); 632 } 633 } 634 635 @Override turnOnProximitySensor()636 public void turnOnProximitySensor() { 637 try { 638 Log.startSession("ICA.tOnPS", mOwnerPackageName); 639 long token = Binder.clearCallingIdentity(); 640 try { 641 synchronized (mLock) { 642 mCallsManager.turnOnProximitySensor(); 643 } 644 } finally { 645 Binder.restoreCallingIdentity(token); 646 } 647 } finally { 648 Log.endSession(); 649 } 650 } 651 652 @Override turnOffProximitySensor(boolean screenOnImmediately)653 public void turnOffProximitySensor(boolean screenOnImmediately) { 654 try { 655 Log.startSession("ICA.tOffPS", mOwnerPackageName); 656 long token = Binder.clearCallingIdentity(); 657 try { 658 synchronized (mLock) { 659 mCallsManager.turnOffProximitySensor(screenOnImmediately); 660 } 661 } finally { 662 Binder.restoreCallingIdentity(token); 663 } 664 } finally { 665 Log.endSession(); 666 } 667 } 668 669 @Override sendRttRequest(String callId)670 public void sendRttRequest(String callId) { 671 try { 672 Log.startSession("ICA.sRR"); 673 long token = Binder.clearCallingIdentity(); 674 try { 675 synchronized (mLock) { 676 Call call = mCallIdMapper.getCall(callId); 677 if (call != null) { 678 call.sendRttRequest(); 679 } else { 680 Log.w(this, "stopRtt(): call %s not found", callId); 681 } 682 } 683 } finally { 684 Binder.restoreCallingIdentity(token); 685 } 686 } finally { 687 Log.endSession(); 688 } 689 } 690 691 @Override respondToRttRequest(String callId, int id, boolean accept)692 public void respondToRttRequest(String callId, int id, boolean accept) { 693 try { 694 Log.startSession("ICA.rTRR"); 695 long token = Binder.clearCallingIdentity(); 696 try { 697 synchronized (mLock) { 698 Call call = mCallIdMapper.getCall(callId); 699 if (call != null) { 700 call.handleRttRequestResponse(id, accept); 701 } else { 702 Log.w(this, "respondToRttRequest(): call %s not found", callId); 703 } 704 } 705 } finally { 706 Binder.restoreCallingIdentity(token); 707 } 708 } finally { 709 Log.endSession(); 710 } 711 } 712 713 @Override stopRtt(String callId)714 public void stopRtt(String callId) { 715 try { 716 Log.startSession("ICA.sRTT"); 717 long token = Binder.clearCallingIdentity(); 718 try { 719 synchronized (mLock) { 720 Call call = mCallIdMapper.getCall(callId); 721 if (call != null) { 722 call.stopRtt(); 723 } else { 724 Log.w(this, "stopRtt(): call %s not found", callId); 725 } 726 } 727 } finally { 728 Binder.restoreCallingIdentity(token); 729 } 730 } finally { 731 Log.endSession(); 732 } 733 } 734 735 @Override setRttMode(String callId, int mode)736 public void setRttMode(String callId, int mode) { 737 try { 738 Log.startSession("ICA.sRM"); 739 long token = Binder.clearCallingIdentity(); 740 try { 741 synchronized (mLock) { 742 // TODO 743 } 744 } finally { 745 Binder.restoreCallingIdentity(token); 746 } 747 } finally { 748 Log.endSession(); 749 } 750 } 751 752 @Override handoverTo(String callId, PhoneAccountHandle destAcct, int videoState, Bundle extras)753 public void handoverTo(String callId, PhoneAccountHandle destAcct, int videoState, 754 Bundle extras) { 755 try { 756 Log.startSession("ICA.hT", mOwnerPackageName); 757 long token = Binder.clearCallingIdentity(); 758 try { 759 synchronized (mLock) { 760 Call call = mCallIdMapper.getCall(callId); 761 if (call != null) { 762 call.handoverTo(destAcct, videoState, extras); 763 } else { 764 Log.w(this, "handoverTo, unknown call id: %s", callId); 765 } 766 } 767 } finally { 768 Binder.restoreCallingIdentity(token); 769 } 770 } finally { 771 Log.endSession(); 772 } 773 } 774 } 775