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