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