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