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