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 // Check to see if this Connection has already been added. 924 Call alreadyAddedConnection = mCallsManager 925 .getAlreadyAddedConnection(connectIdToCheck); 926 927 if (alreadyAddedConnection != null 928 && mCallIdMapper.getCall(callId) == null) { 929 mCallIdMapper.addCall(alreadyAddedConnection, callId); 930 alreadyAddedConnection 931 .replaceConnectionService(ConnectionServiceWrapper.this); 932 return; 933 } 934 935 Call existingCall = mCallsManager 936 .createCallForExistingConnection(callId, connection); 937 mCallIdMapper.addCall(existingCall, callId); 938 existingCall.setConnectionService(ConnectionServiceWrapper.this); 939 } else { 940 Log.e(this, new RemoteException("The PhoneAccount being used is not " + 941 "currently registered with Telecom."), "Unable to " + 942 "addExistingConnection."); 943 } 944 } 945 } catch (Throwable t) { 946 Log.e(ConnectionServiceWrapper.this, t, ""); 947 throw t; 948 } finally { 949 Binder.restoreCallingIdentity(token); 950 Log.endSession(); 951 } 952 } 953 954 @Override onConnectionEvent(String callId, String event, Bundle extras, Session.Info sessionInfo)955 public void onConnectionEvent(String callId, String event, Bundle extras, 956 Session.Info sessionInfo) { 957 Log.startSession(sessionInfo, "CSW.oCE", mPackageAbbreviation); 958 long token = Binder.clearCallingIdentity(); 959 try { 960 synchronized (mLock) { 961 Bundle.setDefusable(extras, true); 962 Call call = mCallIdMapper.getCall(callId); 963 if (call != null) { 964 call.onConnectionEvent(event, extras); 965 } 966 } 967 } catch (Throwable t) { 968 Log.e(ConnectionServiceWrapper.this, t, ""); 969 throw t; 970 } finally { 971 Binder.restoreCallingIdentity(token); 972 Log.endSession(); 973 } 974 } 975 976 @Override onRttInitiationSuccess(String callId, Session.Info sessionInfo)977 public void onRttInitiationSuccess(String callId, Session.Info sessionInfo) 978 throws RemoteException { 979 980 } 981 982 @Override onRttInitiationFailure(String callId, int reason, Session.Info sessionInfo)983 public void onRttInitiationFailure(String callId, int reason, Session.Info sessionInfo) 984 throws RemoteException { 985 Log.startSession(sessionInfo, "CSW.oRIF", mPackageAbbreviation); 986 long token = Binder.clearCallingIdentity(); 987 try { 988 synchronized (mLock) { 989 Call call = mCallIdMapper.getCall(callId); 990 if (call != null) { 991 call.onRttConnectionFailure(reason); 992 } 993 } 994 } catch (Throwable t) { 995 Log.e(ConnectionServiceWrapper.this, t, ""); 996 throw t; 997 } finally { 998 Binder.restoreCallingIdentity(token); 999 Log.endSession(); 1000 } 1001 } 1002 1003 @Override onRttSessionRemotelyTerminated(String callId, Session.Info sessionInfo)1004 public void onRttSessionRemotelyTerminated(String callId, Session.Info sessionInfo) 1005 throws RemoteException { 1006 1007 } 1008 1009 @Override onRemoteRttRequest(String callId, Session.Info sessionInfo)1010 public void onRemoteRttRequest(String callId, Session.Info sessionInfo) 1011 throws RemoteException { 1012 Log.startSession(sessionInfo, "CSW.oRRR", mPackageAbbreviation); 1013 long token = Binder.clearCallingIdentity(); 1014 try { 1015 synchronized (mLock) { 1016 Call call = mCallIdMapper.getCall(callId); 1017 if (call != null) { 1018 call.onRemoteRttRequest(); 1019 } 1020 } 1021 } catch (Throwable t) { 1022 Log.e(ConnectionServiceWrapper.this, t, ""); 1023 throw t; 1024 } finally { 1025 Binder.restoreCallingIdentity(token); 1026 Log.endSession(); 1027 } 1028 } 1029 1030 @Override onPhoneAccountChanged(String callId, PhoneAccountHandle pHandle, Session.Info sessionInfo)1031 public void onPhoneAccountChanged(String callId, PhoneAccountHandle pHandle, 1032 Session.Info sessionInfo) throws RemoteException { 1033 // Check that the Calling Package matches PhoneAccountHandle's Component Package 1034 if (pHandle != null) { 1035 mAppOpsManager.checkPackage(Binder.getCallingUid(), 1036 pHandle.getComponentName().getPackageName()); 1037 } 1038 Log.startSession(sessionInfo, "CSW.oPAC", mPackageAbbreviation); 1039 long token = Binder.clearCallingIdentity(); 1040 try { 1041 synchronized (mLock) { 1042 Call call = mCallIdMapper.getCall(callId); 1043 if (call != null) { 1044 call.setTargetPhoneAccount(pHandle); 1045 } 1046 } 1047 } catch (Throwable t) { 1048 Log.e(ConnectionServiceWrapper.this, t, ""); 1049 throw t; 1050 } finally { 1051 Binder.restoreCallingIdentity(token); 1052 Log.endSession(); 1053 } 1054 } 1055 1056 @Override onConnectionServiceFocusReleased(Session.Info sessionInfo)1057 public void onConnectionServiceFocusReleased(Session.Info sessionInfo) 1058 throws RemoteException { 1059 Log.startSession(sessionInfo, "CSW.oCSFR", mPackageAbbreviation); 1060 long token = Binder.clearCallingIdentity(); 1061 try { 1062 synchronized (mLock) { 1063 mConnSvrFocusListener.onConnectionServiceReleased( 1064 ConnectionServiceWrapper.this); 1065 } 1066 } catch (Throwable t) { 1067 Log.e(ConnectionServiceWrapper.this, t, ""); 1068 throw t; 1069 } finally { 1070 Binder.restoreCallingIdentity(token); 1071 Log.endSession(); 1072 } 1073 } 1074 1075 @Override setConferenceState(String callId, boolean isConference, Session.Info sessionInfo)1076 public void setConferenceState(String callId, boolean isConference, 1077 Session.Info sessionInfo) throws RemoteException { 1078 Log.startSession(sessionInfo, "CSW.sCS", mPackageAbbreviation); 1079 1080 if (mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE) 1081 != PackageManager.PERMISSION_GRANTED) { 1082 Log.w(this, "setConferenceState from caller without permission."); 1083 Log.endSession(); 1084 return; 1085 } 1086 1087 long token = Binder.clearCallingIdentity(); 1088 try { 1089 synchronized (mLock) { 1090 Call call = mCallIdMapper.getCall(callId); 1091 if (call != null) { 1092 call.setConferenceState(isConference); 1093 } 1094 } 1095 } catch (Throwable t) { 1096 Log.e(ConnectionServiceWrapper.this, t, ""); 1097 throw t; 1098 } finally { 1099 Binder.restoreCallingIdentity(token); 1100 Log.endSession(); 1101 } 1102 } 1103 1104 @Override setCallDirection(String callId, int direction, Session.Info sessionInfo)1105 public void setCallDirection(String callId, int direction, Session.Info sessionInfo) { 1106 Log.startSession(sessionInfo, "CSW.sCD", mPackageAbbreviation); 1107 1108 if (mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE) 1109 != PackageManager.PERMISSION_GRANTED) { 1110 Log.w(this, "setCallDirection from caller without permission."); 1111 Log.endSession(); 1112 return; 1113 } 1114 1115 long token = Binder.clearCallingIdentity(); 1116 try { 1117 synchronized (mLock) { 1118 logIncoming("setCallDirection %s %d", callId, direction); 1119 Call call = mCallIdMapper.getCall(callId); 1120 if (call != null) { 1121 call.setCallDirection(Call.getRemappedCallDirection(direction)); 1122 } 1123 } 1124 } catch (Throwable t) { 1125 Log.e(ConnectionServiceWrapper.this, t, ""); 1126 throw t; 1127 } finally { 1128 Binder.restoreCallingIdentity(token); 1129 Log.endSession(); 1130 } 1131 } 1132 } 1133 1134 private final Adapter mAdapter = new Adapter(); 1135 private final CallIdMapper mCallIdMapper = new CallIdMapper(Call::getConnectionId); 1136 private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>(); 1137 1138 private Binder2 mBinder = new Binder2(); 1139 private IConnectionService mServiceInterface; 1140 private final ConnectionServiceRepository mConnectionServiceRepository; 1141 private final PhoneAccountRegistrar mPhoneAccountRegistrar; 1142 private final CallsManager mCallsManager; 1143 private final AppOpsManager mAppOpsManager; 1144 private final Context mContext; 1145 1146 private ConnectionServiceFocusManager.ConnectionServiceFocusListener mConnSvrFocusListener; 1147 1148 /** 1149 * Creates a connection service. 1150 * 1151 * @param componentName The component name of the service with which to bind. 1152 * @param connectionServiceRepository Connection service repository. 1153 * @param phoneAccountRegistrar Phone account registrar 1154 * @param callsManager Calls manager 1155 * @param context The context. 1156 * @param userHandle The {@link UserHandle} to use when binding. 1157 */ ConnectionServiceWrapper( ComponentName componentName, ConnectionServiceRepository connectionServiceRepository, PhoneAccountRegistrar phoneAccountRegistrar, CallsManager callsManager, Context context, TelecomSystem.SyncRoot lock, UserHandle userHandle)1158 ConnectionServiceWrapper( 1159 ComponentName componentName, 1160 ConnectionServiceRepository connectionServiceRepository, 1161 PhoneAccountRegistrar phoneAccountRegistrar, 1162 CallsManager callsManager, 1163 Context context, 1164 TelecomSystem.SyncRoot lock, 1165 UserHandle userHandle) { 1166 super(ConnectionService.SERVICE_INTERFACE, componentName, context, lock, userHandle); 1167 mConnectionServiceRepository = connectionServiceRepository; 1168 phoneAccountRegistrar.addListener(new PhoneAccountRegistrar.Listener() { 1169 // TODO -- Upon changes to PhoneAccountRegistrar, need to re-wire connections 1170 // To do this, we must proxy remote ConnectionService objects 1171 }); 1172 mPhoneAccountRegistrar = phoneAccountRegistrar; 1173 mCallsManager = callsManager; 1174 mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 1175 mContext = context; 1176 } 1177 1178 /** See {@link IConnectionService#addConnectionServiceAdapter}. */ addConnectionServiceAdapter(IConnectionServiceAdapter adapter)1179 private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) { 1180 if (isServiceValid("addConnectionServiceAdapter")) { 1181 try { 1182 logOutgoing("addConnectionServiceAdapter %s", adapter); 1183 mServiceInterface.addConnectionServiceAdapter(adapter, Log.getExternalSession()); 1184 } catch (RemoteException e) { 1185 } 1186 } 1187 } 1188 1189 /** See {@link IConnectionService#removeConnectionServiceAdapter}. */ removeConnectionServiceAdapter(IConnectionServiceAdapter adapter)1190 private void removeConnectionServiceAdapter(IConnectionServiceAdapter adapter) { 1191 if (isServiceValid("removeConnectionServiceAdapter")) { 1192 try { 1193 logOutgoing("removeConnectionServiceAdapter %s", adapter); 1194 mServiceInterface.removeConnectionServiceAdapter(adapter, Log.getExternalSession()); 1195 } catch (RemoteException e) { 1196 } 1197 } 1198 } 1199 1200 /** 1201 * Creates a conference for a new outgoing call or attach to an existing incoming call. 1202 */ createConference(final Call call, final CreateConnectionResponse response)1203 public void createConference(final Call call, final CreateConnectionResponse response) { 1204 Log.d(this, "createConference(%s) via %s.", call, getComponentName()); 1205 BindCallback callback = new BindCallback() { 1206 @Override 1207 public void onSuccess() { 1208 String callId = mCallIdMapper.getCallId(call); 1209 mPendingResponses.put(callId, response); 1210 1211 Bundle extras = call.getIntentExtras(); 1212 if (extras == null) { 1213 extras = new Bundle(); 1214 } 1215 extras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId); 1216 1217 Log.addEvent(call, LogUtils.Events.START_CONFERENCE, 1218 Log.piiHandle(call.getHandle())); 1219 1220 ConnectionRequest connectionRequest = new ConnectionRequest.Builder() 1221 .setAccountHandle(call.getTargetPhoneAccount()) 1222 .setAddress(call.getHandle()) 1223 .setExtras(extras) 1224 .setVideoState(call.getVideoState()) 1225 .setTelecomCallId(callId) 1226 // For self-managed incoming calls, if there is another ongoing call Telecom 1227 // is responsible for showing a UI to ask the user if they'd like to answer 1228 // this new incoming call. 1229 .setShouldShowIncomingCallUi( 1230 !mCallsManager.shouldShowSystemIncomingCallUi(call)) 1231 .setRttPipeFromInCall(call.getInCallToCsRttPipeForCs()) 1232 .setRttPipeToInCall(call.getCsToInCallRttPipeForCs()) 1233 .setParticipants(call.getParticipants()) 1234 .setIsAdhocConferenceCall(call.isAdhocConferenceCall()) 1235 .build(); 1236 1237 try { 1238 mServiceInterface.createConference( 1239 call.getConnectionManagerPhoneAccount(), 1240 callId, 1241 connectionRequest, 1242 call.shouldAttachToExistingConnection(), 1243 call.isUnknown(), 1244 Log.getExternalSession(TELECOM_ABBREVIATION)); 1245 1246 } catch (RemoteException e) { 1247 Log.e(this, e, "Failure to createConference -- %s", getComponentName()); 1248 mPendingResponses.remove(callId).handleCreateConferenceFailure( 1249 new DisconnectCause(DisconnectCause.ERROR, e.toString())); 1250 } 1251 } 1252 1253 @Override 1254 public void onFailure() { 1255 Log.e(this, new Exception(), "Failure to conference %s", getComponentName()); 1256 response.handleCreateConferenceFailure(new DisconnectCause(DisconnectCause.ERROR)); 1257 } 1258 }; 1259 1260 mBinder.bind(callback, call); 1261 1262 } 1263 1264 /** 1265 * Creates a new connection for a new outgoing call or to attach to an existing incoming call. 1266 */ 1267 @VisibleForTesting createConnection(final Call call, final CreateConnectionResponse response)1268 public void createConnection(final Call call, final CreateConnectionResponse response) { 1269 Log.i(this, "createConnection(%s) via %s.", call, getComponentName()); 1270 BindCallback callback = new BindCallback() { 1271 @Override 1272 public void onSuccess() { 1273 String callId = mCallIdMapper.getCallId(call); 1274 if (callId == null) { 1275 Log.w(ConnectionServiceWrapper.this, "Call not present" 1276 + " in call id mapper, maybe it was aborted before the bind" 1277 + " completed successfully?"); 1278 response.handleCreateConnectionFailure( 1279 new DisconnectCause(DisconnectCause.CANCELED)); 1280 return; 1281 } 1282 mPendingResponses.put(callId, response); 1283 1284 GatewayInfo gatewayInfo = call.getGatewayInfo(); 1285 Bundle extras = call.getIntentExtras(); 1286 if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null && 1287 gatewayInfo.getOriginalAddress() != null) { 1288 extras = (Bundle) extras.clone(); 1289 extras.putString( 1290 TelecomManager.GATEWAY_PROVIDER_PACKAGE, 1291 gatewayInfo.getGatewayProviderPackageName()); 1292 extras.putParcelable( 1293 TelecomManager.GATEWAY_ORIGINAL_ADDRESS, 1294 gatewayInfo.getOriginalAddress()); 1295 } 1296 1297 if (call.isIncoming() && mCallsManager.getEmergencyCallHelper() 1298 .getLastEmergencyCallTimeMillis() > 0) { 1299 // Add the last emergency call time to the connection request for incoming calls 1300 if (extras == call.getIntentExtras()) { 1301 extras = (Bundle) extras.clone(); 1302 } 1303 extras.putLong(android.telecom.Call.EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS, 1304 mCallsManager.getEmergencyCallHelper().getLastEmergencyCallTimeMillis()); 1305 } 1306 1307 // Call is incoming and added because we're handing over from another; tell CS 1308 // that its expected to handover. 1309 if (call.isIncoming() && call.getHandoverSourceCall() != null) { 1310 extras.putBoolean(TelecomManager.EXTRA_IS_HANDOVER, true); 1311 extras.putParcelable(TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT, 1312 call.getHandoverSourceCall().getTargetPhoneAccount()); 1313 } 1314 1315 Log.addEvent(call, LogUtils.Events.START_CONNECTION, 1316 Log.piiHandle(call.getHandle()) + " via:" + 1317 getComponentName().getPackageName()); 1318 1319 ConnectionRequest connectionRequest = new ConnectionRequest.Builder() 1320 .setAccountHandle(call.getTargetPhoneAccount()) 1321 .setAddress(call.getHandle()) 1322 .setExtras(extras) 1323 .setVideoState(call.getVideoState()) 1324 .setTelecomCallId(callId) 1325 // For self-managed incoming calls, if there is another ongoing call Telecom 1326 // is responsible for showing a UI to ask the user if they'd like to answer 1327 // this new incoming call. 1328 .setShouldShowIncomingCallUi( 1329 !mCallsManager.shouldShowSystemIncomingCallUi(call)) 1330 .setRttPipeFromInCall(call.getInCallToCsRttPipeForCs()) 1331 .setRttPipeToInCall(call.getCsToInCallRttPipeForCs()) 1332 .build(); 1333 1334 try { 1335 mServiceInterface.createConnection( 1336 call.getConnectionManagerPhoneAccount(), 1337 callId, 1338 connectionRequest, 1339 call.shouldAttachToExistingConnection(), 1340 call.isUnknown(), 1341 Log.getExternalSession(TELECOM_ABBREVIATION)); 1342 1343 } catch (RemoteException e) { 1344 Log.e(this, e, "Failure to createConnection -- %s", getComponentName()); 1345 mPendingResponses.remove(callId).handleCreateConnectionFailure( 1346 new DisconnectCause(DisconnectCause.ERROR, e.toString())); 1347 } 1348 } 1349 1350 @Override 1351 public void onFailure() { 1352 Log.e(this, new Exception(), "Failure to call %s", getComponentName()); 1353 response.handleCreateConnectionFailure(new DisconnectCause(DisconnectCause.ERROR)); 1354 } 1355 }; 1356 1357 mBinder.bind(callback, call); 1358 } 1359 1360 /** 1361 * Notifies the {@link ConnectionService} associated with a {@link Call} that the request to 1362 * create a connection has been denied or failed. 1363 * @param call The call. 1364 */ 1365 @VisibleForTesting createConnectionFailed(final Call call)1366 public void createConnectionFailed(final Call call) { 1367 Log.d(this, "createConnectionFailed(%s) via %s.", call, getComponentName()); 1368 BindCallback callback = new BindCallback() { 1369 @Override 1370 public void onSuccess() { 1371 final String callId = mCallIdMapper.getCallId(call); 1372 // If still bound, tell the connection service create connection has failed. 1373 if (callId != null && isServiceValid("createConnectionFailed")) { 1374 Log.addEvent(call, LogUtils.Events.CREATE_CONNECTION_FAILED, 1375 Log.piiHandle(call.getHandle())); 1376 try { 1377 logOutgoing("createConnectionFailed %s", callId); 1378 mServiceInterface.createConnectionFailed( 1379 call.getConnectionManagerPhoneAccount(), 1380 callId, 1381 new ConnectionRequest( 1382 call.getTargetPhoneAccount(), 1383 call.getHandle(), 1384 call.getIntentExtras(), 1385 call.getVideoState(), 1386 callId, 1387 false), 1388 call.isIncoming(), 1389 Log.getExternalSession(TELECOM_ABBREVIATION)); 1390 call.setDisconnectCause(new DisconnectCause(DisconnectCause.CANCELED)); 1391 call.disconnect(); 1392 } catch (RemoteException e) { 1393 } 1394 } 1395 } 1396 1397 @Override 1398 public void onFailure() { 1399 // Binding failed. Oh no. 1400 Log.w(this, "onFailure - could not bind to CS for call %s", call.getId()); 1401 } 1402 }; 1403 1404 mBinder.bind(callback, call); 1405 } 1406 1407 /** 1408 * Notifies the {@link ConnectionService} associated with a {@link Call} that the request to 1409 * create a conference has been denied or failed. 1410 * @param call The call. 1411 */ createConferenceFailed(final Call call)1412 void createConferenceFailed(final Call call) { 1413 Log.d(this, "createConferenceFailed(%s) via %s.", call, getComponentName()); 1414 BindCallback callback = new BindCallback() { 1415 @Override 1416 public void onSuccess() { 1417 final String callId = mCallIdMapper.getCallId(call); 1418 // If still bound, tell the connection service create connection has failed. 1419 if (callId != null && isServiceValid("createConferenceFailed")) { 1420 Log.addEvent(call, LogUtils.Events.CREATE_CONFERENCE_FAILED, 1421 Log.piiHandle(call.getHandle())); 1422 try { 1423 logOutgoing("createConferenceFailed %s", callId); 1424 mServiceInterface.createConferenceFailed( 1425 call.getConnectionManagerPhoneAccount(), 1426 callId, 1427 new ConnectionRequest( 1428 call.getTargetPhoneAccount(), 1429 call.getHandle(), 1430 call.getIntentExtras(), 1431 call.getVideoState(), 1432 callId, 1433 false), 1434 call.isIncoming(), 1435 Log.getExternalSession(TELECOM_ABBREVIATION)); 1436 call.setDisconnectCause(new DisconnectCause(DisconnectCause.CANCELED)); 1437 call.disconnect(); 1438 } catch (RemoteException e) { 1439 } 1440 } 1441 } 1442 1443 @Override 1444 public void onFailure() { 1445 // Binding failed. Oh no. 1446 Log.w(this, "onFailure - could not bind to CS for conf call %s", call.getId()); 1447 } 1448 }; 1449 1450 mBinder.bind(callback, call); 1451 } 1452 1453 handoverFailed(final Call call, final int reason)1454 void handoverFailed(final Call call, final int reason) { 1455 Log.d(this, "handoverFailed(%s) via %s.", call, getComponentName()); 1456 BindCallback callback = new BindCallback() { 1457 @Override 1458 public void onSuccess() { 1459 final String callId = mCallIdMapper.getCallId(call); 1460 // If still bound, tell the connection service create connection has failed. 1461 if (callId != null && isServiceValid("handoverFailed")) { 1462 Log.addEvent(call, LogUtils.Events.HANDOVER_FAILED, 1463 Log.piiHandle(call.getHandle())); 1464 try { 1465 mServiceInterface.handoverFailed( 1466 callId, 1467 new ConnectionRequest( 1468 call.getTargetPhoneAccount(), 1469 call.getHandle(), 1470 call.getIntentExtras(), 1471 call.getVideoState(), 1472 callId, 1473 false), 1474 reason, 1475 Log.getExternalSession(TELECOM_ABBREVIATION)); 1476 } catch (RemoteException e) { 1477 } 1478 } 1479 } 1480 1481 @Override 1482 public void onFailure() { 1483 // Binding failed. 1484 Log.w(this, "onFailure - could not bind to CS for call %s", 1485 call.getId()); 1486 } 1487 }; 1488 1489 mBinder.bind(callback, call); 1490 } 1491 handoverComplete(final Call call)1492 void handoverComplete(final Call call) { 1493 Log.d(this, "handoverComplete(%s) via %s.", call, getComponentName()); 1494 BindCallback callback = new BindCallback() { 1495 @Override 1496 public void onSuccess() { 1497 final String callId = mCallIdMapper.getCallId(call); 1498 // If still bound, tell the connection service create connection has failed. 1499 if (callId != null && isServiceValid("handoverComplete")) { 1500 try { 1501 mServiceInterface.handoverComplete( 1502 callId, 1503 Log.getExternalSession(TELECOM_ABBREVIATION)); 1504 } catch (RemoteException e) { 1505 } 1506 } 1507 } 1508 1509 @Override 1510 public void onFailure() { 1511 // Binding failed. 1512 Log.w(this, "onFailure - could not bind to CS for call %s", 1513 call.getId()); 1514 } 1515 }; 1516 1517 mBinder.bind(callback, call); 1518 } 1519 1520 /** @see IConnectionService#abort(String, Session.Info) */ abort(Call call)1521 void abort(Call call) { 1522 // Clear out any pending outgoing call data 1523 final String callId = mCallIdMapper.getCallId(call); 1524 1525 // If still bound, tell the connection service to abort. 1526 if (callId != null && isServiceValid("abort")) { 1527 try { 1528 logOutgoing("abort %s", callId); 1529 mServiceInterface.abort(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 1530 } catch (RemoteException e) { 1531 } 1532 } 1533 1534 removeCall(call, new DisconnectCause(DisconnectCause.LOCAL)); 1535 } 1536 1537 /** @see IConnectionService#silence(String, Session.Info) */ silence(Call call)1538 void silence(Call call) { 1539 final String callId = mCallIdMapper.getCallId(call); 1540 if (callId != null && isServiceValid("silence")) { 1541 try { 1542 logOutgoing("silence %s", callId); 1543 mServiceInterface.silence(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 1544 } catch (RemoteException e) { 1545 } 1546 } 1547 } 1548 1549 /** @see IConnectionService#hold(String, Session.Info) */ hold(Call call)1550 void hold(Call call) { 1551 final String callId = mCallIdMapper.getCallId(call); 1552 if (callId != null && isServiceValid("hold")) { 1553 try { 1554 logOutgoing("hold %s", callId); 1555 mServiceInterface.hold(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 1556 } catch (RemoteException e) { 1557 } 1558 } 1559 } 1560 1561 /** @see IConnectionService#unhold(String, Session.Info) */ unhold(Call call)1562 void unhold(Call call) { 1563 final String callId = mCallIdMapper.getCallId(call); 1564 if (callId != null && isServiceValid("unhold")) { 1565 try { 1566 logOutgoing("unhold %s", callId); 1567 mServiceInterface.unhold(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 1568 } catch (RemoteException e) { 1569 } 1570 } 1571 } 1572 1573 /** @see IConnectionService#onCallAudioStateChanged(String, CallAudioState, Session.Info) */ 1574 @VisibleForTesting onCallAudioStateChanged(Call activeCall, CallAudioState audioState)1575 public void onCallAudioStateChanged(Call activeCall, CallAudioState audioState) { 1576 final String callId = mCallIdMapper.getCallId(activeCall); 1577 if (callId != null && isServiceValid("onCallAudioStateChanged")) { 1578 try { 1579 logOutgoing("onCallAudioStateChanged %s %s", callId, audioState); 1580 mServiceInterface.onCallAudioStateChanged(callId, audioState, 1581 Log.getExternalSession(TELECOM_ABBREVIATION)); 1582 } catch (RemoteException e) { 1583 } 1584 } 1585 } 1586 1587 /** @see IConnectionService#onUsingAlternativeUi(String, boolean, Session.Info) */ 1588 @VisibleForTesting onUsingAlternativeUi(Call activeCall, boolean isUsingAlternativeUi)1589 public void onUsingAlternativeUi(Call activeCall, boolean isUsingAlternativeUi) { 1590 final String callId = mCallIdMapper.getCallId(activeCall); 1591 if (callId != null && isServiceValid("onUsingAlternativeUi")) { 1592 try { 1593 logOutgoing("onUsingAlternativeUi %s", isUsingAlternativeUi); 1594 mServiceInterface.onUsingAlternativeUi(callId, isUsingAlternativeUi, 1595 Log.getExternalSession(TELECOM_ABBREVIATION)); 1596 } catch (RemoteException e) { 1597 } 1598 } 1599 } 1600 1601 /** @see IConnectionService#onTrackedByNonUiService(String, boolean, Session.Info) */ 1602 @VisibleForTesting onTrackedByNonUiService(Call activeCall, boolean isTracked)1603 public void onTrackedByNonUiService(Call activeCall, boolean isTracked) { 1604 final String callId = mCallIdMapper.getCallId(activeCall); 1605 if (callId != null && isServiceValid("onTrackedByNonUiService")) { 1606 try { 1607 logOutgoing("onTrackedByNonUiService %s", isTracked); 1608 mServiceInterface.onTrackedByNonUiService(callId, isTracked, 1609 Log.getExternalSession(TELECOM_ABBREVIATION)); 1610 } catch (RemoteException e) { 1611 } 1612 } 1613 } 1614 1615 /** @see IConnectionService#disconnect(String, Session.Info) */ disconnect(Call call)1616 void disconnect(Call call) { 1617 final String callId = mCallIdMapper.getCallId(call); 1618 if (callId != null && isServiceValid("disconnect")) { 1619 try { 1620 logOutgoing("disconnect %s", callId); 1621 mServiceInterface.disconnect(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 1622 } catch (RemoteException e) { 1623 } 1624 } 1625 } 1626 1627 /** @see IConnectionService#answer(String, Session.Info) */ answer(Call call, int videoState)1628 void answer(Call call, int videoState) { 1629 final String callId = mCallIdMapper.getCallId(call); 1630 if (callId != null && isServiceValid("answer")) { 1631 try { 1632 logOutgoing("answer %s %d", callId, videoState); 1633 if (VideoProfile.isAudioOnly(videoState)) { 1634 mServiceInterface.answer(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 1635 } else { 1636 mServiceInterface.answerVideo(callId, videoState, 1637 Log.getExternalSession(TELECOM_ABBREVIATION)); 1638 } 1639 } catch (RemoteException e) { 1640 } 1641 } 1642 } 1643 1644 /** @see IConnectionService#deflect(String, Uri , Session.Info) */ deflect(Call call, Uri address)1645 void deflect(Call call, Uri address) { 1646 final String callId = mCallIdMapper.getCallId(call); 1647 if (callId != null && isServiceValid("deflect")) { 1648 try { 1649 logOutgoing("deflect %s", callId); 1650 mServiceInterface.deflect(callId, address, 1651 Log.getExternalSession(TELECOM_ABBREVIATION)); 1652 } catch (RemoteException e) { 1653 } 1654 } 1655 } 1656 1657 /** @see IConnectionService#reject(String, Session.Info) */ reject(Call call, boolean rejectWithMessage, String message)1658 void reject(Call call, boolean rejectWithMessage, String message) { 1659 final String callId = mCallIdMapper.getCallId(call); 1660 if (callId != null && isServiceValid("reject")) { 1661 try { 1662 logOutgoing("reject %s", callId); 1663 1664 if (rejectWithMessage && call.can( 1665 Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) { 1666 mServiceInterface.rejectWithMessage(callId, message, 1667 Log.getExternalSession(TELECOM_ABBREVIATION)); 1668 } else { 1669 mServiceInterface.reject(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 1670 } 1671 } catch (RemoteException e) { 1672 } 1673 } 1674 } 1675 1676 /** @see IConnectionService#reject(String, Session.Info) */ rejectWithReason(Call call, @android.telecom.Call.RejectReason int rejectReason)1677 void rejectWithReason(Call call, @android.telecom.Call.RejectReason int rejectReason) { 1678 final String callId = mCallIdMapper.getCallId(call); 1679 if (callId != null && isServiceValid("rejectReason")) { 1680 try { 1681 logOutgoing("rejectReason %s, %d", callId, rejectReason); 1682 1683 mServiceInterface.rejectWithReason(callId, rejectReason, 1684 Log.getExternalSession(TELECOM_ABBREVIATION)); 1685 } catch (RemoteException e) { 1686 } 1687 } 1688 } 1689 1690 /** @see IConnectionService#transfer(String, Uri , boolean, Session.Info) */ transfer(Call call, Uri number, boolean isConfirmationRequired)1691 void transfer(Call call, Uri number, boolean isConfirmationRequired) { 1692 final String callId = mCallIdMapper.getCallId(call); 1693 if (callId != null && isServiceValid("transfer")) { 1694 try { 1695 logOutgoing("transfer %s", callId); 1696 mServiceInterface.transfer(callId, number, isConfirmationRequired, 1697 Log.getExternalSession(TELECOM_ABBREVIATION)); 1698 } catch (RemoteException e) { 1699 } 1700 } 1701 } 1702 1703 /** @see IConnectionService#consultativeTransfer(String, String, Session.Info) */ transfer(Call call, Call otherCall)1704 void transfer(Call call, Call otherCall) { 1705 final String callId = mCallIdMapper.getCallId(call); 1706 final String otherCallId = mCallIdMapper.getCallId(otherCall); 1707 if (callId != null && otherCallId != null && isServiceValid("consultativeTransfer")) { 1708 try { 1709 logOutgoing("consultativeTransfer %s", callId); 1710 mServiceInterface.consultativeTransfer(callId, otherCallId, 1711 Log.getExternalSession(TELECOM_ABBREVIATION)); 1712 } catch (RemoteException e) { 1713 } 1714 } 1715 } 1716 1717 /** @see IConnectionService#playDtmfTone(String, char, Session.Info) */ playDtmfTone(Call call, char digit)1718 void playDtmfTone(Call call, char digit) { 1719 final String callId = mCallIdMapper.getCallId(call); 1720 if (callId != null && isServiceValid("playDtmfTone")) { 1721 try { 1722 logOutgoing("playDtmfTone %s %c", callId, digit); 1723 mServiceInterface.playDtmfTone(callId, digit, 1724 Log.getExternalSession(TELECOM_ABBREVIATION)); 1725 } catch (RemoteException e) { 1726 } 1727 } 1728 } 1729 1730 /** @see IConnectionService#stopDtmfTone(String, Session.Info) */ stopDtmfTone(Call call)1731 void stopDtmfTone(Call call) { 1732 final String callId = mCallIdMapper.getCallId(call); 1733 if (callId != null && isServiceValid("stopDtmfTone")) { 1734 try { 1735 logOutgoing("stopDtmfTone %s", callId); 1736 mServiceInterface.stopDtmfTone(callId, 1737 Log.getExternalSession(TELECOM_ABBREVIATION)); 1738 } catch (RemoteException e) { 1739 } 1740 } 1741 } 1742 addCall(Call call)1743 void addCall(Call call) { 1744 if (mCallIdMapper.getCallId(call) == null) { 1745 mCallIdMapper.addCall(call); 1746 } 1747 } 1748 1749 /** 1750 * Associates newCall with this connection service by replacing callToReplace. 1751 */ replaceCall(Call newCall, Call callToReplace)1752 void replaceCall(Call newCall, Call callToReplace) { 1753 Preconditions.checkState(callToReplace.getConnectionService() == this); 1754 mCallIdMapper.replaceCall(newCall, callToReplace); 1755 } 1756 removeCall(Call call)1757 void removeCall(Call call) { 1758 removeCall(call, new DisconnectCause(DisconnectCause.ERROR)); 1759 } 1760 removeCall(String callId, DisconnectCause disconnectCause)1761 void removeCall(String callId, DisconnectCause disconnectCause) { 1762 CreateConnectionResponse response = mPendingResponses.remove(callId); 1763 if (response != null) { 1764 response.handleCreateConnectionFailure(disconnectCause); 1765 } 1766 1767 mCallIdMapper.removeCall(callId); 1768 } 1769 removeCall(Call call, DisconnectCause disconnectCause)1770 void removeCall(Call call, DisconnectCause disconnectCause) { 1771 CreateConnectionResponse response = mPendingResponses.remove(mCallIdMapper.getCallId(call)); 1772 if (response != null) { 1773 response.handleCreateConnectionFailure(disconnectCause); 1774 } 1775 1776 mCallIdMapper.removeCall(call); 1777 } 1778 onPostDialContinue(Call call, boolean proceed)1779 void onPostDialContinue(Call call, boolean proceed) { 1780 final String callId = mCallIdMapper.getCallId(call); 1781 if (callId != null && isServiceValid("onPostDialContinue")) { 1782 try { 1783 logOutgoing("onPostDialContinue %s %b", callId, proceed); 1784 mServiceInterface.onPostDialContinue(callId, proceed, 1785 Log.getExternalSession(TELECOM_ABBREVIATION)); 1786 } catch (RemoteException ignored) { 1787 } 1788 } 1789 } 1790 conference(final Call call, Call otherCall)1791 void conference(final Call call, Call otherCall) { 1792 final String callId = mCallIdMapper.getCallId(call); 1793 final String otherCallId = mCallIdMapper.getCallId(otherCall); 1794 if (callId != null && otherCallId != null && isServiceValid("conference")) { 1795 try { 1796 logOutgoing("conference %s %s", callId, otherCallId); 1797 mServiceInterface.conference(callId, otherCallId, 1798 Log.getExternalSession(TELECOM_ABBREVIATION)); 1799 } catch (RemoteException ignored) { 1800 } 1801 } 1802 } 1803 splitFromConference(Call call)1804 void splitFromConference(Call call) { 1805 final String callId = mCallIdMapper.getCallId(call); 1806 if (callId != null && isServiceValid("splitFromConference")) { 1807 try { 1808 logOutgoing("splitFromConference %s", callId); 1809 mServiceInterface.splitFromConference(callId, 1810 Log.getExternalSession(TELECOM_ABBREVIATION)); 1811 } catch (RemoteException ignored) { 1812 } 1813 } 1814 } 1815 mergeConference(Call call)1816 void mergeConference(Call call) { 1817 final String callId = mCallIdMapper.getCallId(call); 1818 if (callId != null && isServiceValid("mergeConference")) { 1819 try { 1820 logOutgoing("mergeConference %s", callId); 1821 mServiceInterface.mergeConference(callId, 1822 Log.getExternalSession(TELECOM_ABBREVIATION)); 1823 } catch (RemoteException ignored) { 1824 } 1825 } 1826 } 1827 swapConference(Call call)1828 void swapConference(Call call) { 1829 final String callId = mCallIdMapper.getCallId(call); 1830 if (callId != null && isServiceValid("swapConference")) { 1831 try { 1832 logOutgoing("swapConference %s", callId); 1833 mServiceInterface.swapConference(callId, 1834 Log.getExternalSession(TELECOM_ABBREVIATION)); 1835 } catch (RemoteException ignored) { 1836 } 1837 } 1838 } 1839 addConferenceParticipants(Call call, List<Uri> participants)1840 void addConferenceParticipants(Call call, List<Uri> participants) { 1841 final String callId = mCallIdMapper.getCallId(call); 1842 if (callId != null && isServiceValid("addConferenceParticipants")) { 1843 try { 1844 logOutgoing("addConferenceParticipants %s", callId); 1845 mServiceInterface.addConferenceParticipants(callId, participants, 1846 Log.getExternalSession(TELECOM_ABBREVIATION)); 1847 } catch (RemoteException ignored) { 1848 } 1849 } 1850 } 1851 1852 @VisibleForTesting pullExternalCall(Call call)1853 public void pullExternalCall(Call call) { 1854 final String callId = mCallIdMapper.getCallId(call); 1855 if (callId != null && isServiceValid("pullExternalCall")) { 1856 try { 1857 logOutgoing("pullExternalCall %s", callId); 1858 mServiceInterface.pullExternalCall(callId, 1859 Log.getExternalSession(TELECOM_ABBREVIATION)); 1860 } catch (RemoteException ignored) { 1861 } 1862 } 1863 } 1864 sendCallEvent(Call call, String event, Bundle extras)1865 void sendCallEvent(Call call, String event, Bundle extras) { 1866 final String callId = mCallIdMapper.getCallId(call); 1867 if (callId != null && isServiceValid("sendCallEvent")) { 1868 try { 1869 logOutgoing("sendCallEvent %s %s", callId, event); 1870 mServiceInterface.sendCallEvent(callId, event, extras, 1871 Log.getExternalSession(TELECOM_ABBREVIATION)); 1872 } catch (RemoteException ignored) { 1873 } 1874 } 1875 } 1876 onCallFilteringCompleted(Call call, Connection.CallFilteringCompletionInfo completionInfo)1877 void onCallFilteringCompleted(Call call, 1878 Connection.CallFilteringCompletionInfo completionInfo) { 1879 final String callId = mCallIdMapper.getCallId(call); 1880 if (callId != null && isServiceValid("onCallFilteringCompleted")) { 1881 try { 1882 logOutgoing("onCallFilteringCompleted %s", completionInfo); 1883 int contactsPermission = mContext.getPackageManager() 1884 .checkPermission(Manifest.permission.READ_CONTACTS, 1885 getComponentName().getPackageName()); 1886 if (contactsPermission == PackageManager.PERMISSION_GRANTED) { 1887 mServiceInterface.onCallFilteringCompleted(callId, completionInfo, 1888 Log.getExternalSession(TELECOM_ABBREVIATION)); 1889 } else { 1890 logOutgoing("Skipping call filtering complete message for %s due" 1891 + " to lack of READ_CONTACTS", getComponentName().getPackageName()); 1892 } 1893 } catch (RemoteException e) { 1894 Log.e(this, e, "Remote exception calling onCallFilteringCompleted"); 1895 } 1896 } 1897 } 1898 onExtrasChanged(Call call, Bundle extras)1899 void onExtrasChanged(Call call, Bundle extras) { 1900 final String callId = mCallIdMapper.getCallId(call); 1901 if (callId != null && isServiceValid("onExtrasChanged")) { 1902 try { 1903 logOutgoing("onExtrasChanged %s %s", callId, extras); 1904 mServiceInterface.onExtrasChanged(callId, extras, 1905 Log.getExternalSession(TELECOM_ABBREVIATION)); 1906 } catch (RemoteException ignored) { 1907 } 1908 } 1909 } 1910 startRtt(Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall)1911 void startRtt(Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall) { 1912 final String callId = mCallIdMapper.getCallId(call); 1913 if (callId != null && isServiceValid("startRtt")) { 1914 try { 1915 logOutgoing("startRtt: %s %s %s", callId, fromInCall, toInCall); 1916 mServiceInterface.startRtt(callId, fromInCall, toInCall, 1917 Log.getExternalSession(TELECOM_ABBREVIATION)); 1918 } catch (RemoteException ignored) { 1919 } 1920 } 1921 } 1922 stopRtt(Call call)1923 void stopRtt(Call call) { 1924 final String callId = mCallIdMapper.getCallId(call); 1925 if (callId != null && isServiceValid("stopRtt")) { 1926 try { 1927 logOutgoing("stopRtt: %s", callId); 1928 mServiceInterface.stopRtt(callId, Log.getExternalSession(TELECOM_ABBREVIATION)); 1929 } catch (RemoteException ignored) { 1930 } 1931 } 1932 } 1933 respondToRttRequest( Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall)1934 void respondToRttRequest( 1935 Call call, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall) { 1936 final String callId = mCallIdMapper.getCallId(call); 1937 if (callId != null && isServiceValid("respondToRttRequest")) { 1938 try { 1939 logOutgoing("respondToRttRequest: %s %s %s", callId, fromInCall, toInCall); 1940 mServiceInterface.respondToRttUpgradeRequest( 1941 callId, fromInCall, toInCall, Log.getExternalSession(TELECOM_ABBREVIATION)); 1942 } catch (RemoteException ignored) { 1943 } 1944 } 1945 } 1946 1947 /** {@inheritDoc} */ 1948 @Override setServiceInterface(IBinder binder)1949 protected void setServiceInterface(IBinder binder) { 1950 mServiceInterface = IConnectionService.Stub.asInterface(binder); 1951 Log.v(this, "Adding Connection Service Adapter."); 1952 addConnectionServiceAdapter(mAdapter); 1953 } 1954 1955 /** {@inheritDoc} */ 1956 @Override removeServiceInterface()1957 protected void removeServiceInterface() { 1958 Log.v(this, "Removing Connection Service Adapter."); 1959 removeConnectionServiceAdapter(mAdapter); 1960 // We have lost our service connection. Notify the world that this service is done. 1961 // We must notify the adapter before CallsManager. The adapter will force any pending 1962 // outgoing calls to try the next service. This needs to happen before CallsManager 1963 // tries to clean up any calls still associated with this service. 1964 handleConnectionServiceDeath(); 1965 mCallsManager.handleConnectionServiceDeath(this); 1966 mServiceInterface = null; 1967 } 1968 1969 @Override connectionServiceFocusLost()1970 public void connectionServiceFocusLost() { 1971 // Immediately response to the Telecom that it has released the call resources. 1972 // TODO(mpq): Change back to the default implementation once b/69651192 done. 1973 if (mConnSvrFocusListener != null) { 1974 mConnSvrFocusListener.onConnectionServiceReleased(ConnectionServiceWrapper.this); 1975 } 1976 BindCallback callback = new BindCallback() { 1977 @Override 1978 public void onSuccess() { 1979 try { 1980 mServiceInterface.connectionServiceFocusLost( 1981 Log.getExternalSession(TELECOM_ABBREVIATION)); 1982 } catch (RemoteException ignored) { 1983 Log.d(this, "failed to inform the focus lost event"); 1984 } 1985 } 1986 1987 @Override 1988 public void onFailure() {} 1989 }; 1990 mBinder.bind(callback, null /* null call */); 1991 } 1992 1993 @Override connectionServiceFocusGained()1994 public void connectionServiceFocusGained() { 1995 BindCallback callback = new BindCallback() { 1996 @Override 1997 public void onSuccess() { 1998 try { 1999 mServiceInterface.connectionServiceFocusGained( 2000 Log.getExternalSession(TELECOM_ABBREVIATION)); 2001 } catch (RemoteException ignored) { 2002 Log.d(this, "failed to inform the focus gained event"); 2003 } 2004 } 2005 2006 @Override 2007 public void onFailure() {} 2008 }; 2009 mBinder.bind(callback, null /* null call */); 2010 } 2011 2012 @Override setConnectionServiceFocusListener( ConnectionServiceFocusManager.ConnectionServiceFocusListener listener)2013 public void setConnectionServiceFocusListener( 2014 ConnectionServiceFocusManager.ConnectionServiceFocusListener listener) { 2015 mConnSvrFocusListener = listener; 2016 } 2017 handleCreateConnectionComplete( String callId, ConnectionRequest request, ParcelableConnection connection)2018 private void handleCreateConnectionComplete( 2019 String callId, 2020 ConnectionRequest request, 2021 ParcelableConnection connection) { 2022 // TODO: Note we are not using parameter "request", which is a side effect of our tacit 2023 // assumption that we have at most one outgoing connection attempt per ConnectionService. 2024 // This may not continue to be the case. 2025 if (connection.getState() == Connection.STATE_DISCONNECTED) { 2026 // A connection that begins in the DISCONNECTED state is an indication of 2027 // failure to connect; we handle all failures uniformly 2028 Call foundCall = mCallIdMapper.getCall(callId); 2029 2030 if (connection.getConnectTimeMillis() != 0) { 2031 foundCall.setConnectTimeMillis(connection.getConnectTimeMillis()); 2032 } 2033 2034 if (foundCall != null) { 2035 // The post-dial digits are created when the call is first created. Normally 2036 // the ConnectionService is responsible for stripping them from the address, but 2037 // since a failed connection will not have done this, we could end up with duplicate 2038 // post-dial digits. 2039 foundCall.clearPostDialDigits(); 2040 } 2041 removeCall(callId, connection.getDisconnectCause()); 2042 } else { 2043 // Successful connection 2044 if (mPendingResponses.containsKey(callId)) { 2045 mPendingResponses.remove(callId) 2046 .handleCreateConnectionSuccess(mCallIdMapper, connection); 2047 } 2048 } 2049 } 2050 handleCreateConferenceComplete( String callId, ConnectionRequest request, ParcelableConference conference)2051 private void handleCreateConferenceComplete( 2052 String callId, 2053 ConnectionRequest request, 2054 ParcelableConference conference) { 2055 // TODO: Note we are not using parameter "request", which is a side effect of our tacit 2056 // assumption that we have at most one outgoing conference attempt per ConnectionService. 2057 // This may not continue to be the case. 2058 if (conference.getState() == Connection.STATE_DISCONNECTED) { 2059 // A conference that begins in the DISCONNECTED state is an indication of 2060 // failure to connect; we handle all failures uniformly 2061 removeCall(callId, conference.getDisconnectCause()); 2062 } else { 2063 // Successful connection 2064 if (mPendingResponses.containsKey(callId)) { 2065 mPendingResponses.remove(callId) 2066 .handleCreateConferenceSuccess(mCallIdMapper, conference); 2067 } 2068 } 2069 } 2070 2071 /** 2072 * Called when the associated connection service dies. 2073 */ handleConnectionServiceDeath()2074 private void handleConnectionServiceDeath() { 2075 if (!mPendingResponses.isEmpty()) { 2076 CreateConnectionResponse[] responses = mPendingResponses.values().toArray( 2077 new CreateConnectionResponse[mPendingResponses.values().size()]); 2078 mPendingResponses.clear(); 2079 for (int i = 0; i < responses.length; i++) { 2080 responses[i].handleCreateConnectionFailure( 2081 new DisconnectCause(DisconnectCause.ERROR, "CS_DEATH")); 2082 } 2083 } 2084 mCallIdMapper.clear(); 2085 2086 if (mConnSvrFocusListener != null) { 2087 mConnSvrFocusListener.onConnectionServiceDeath(this); 2088 } 2089 } 2090 logIncoming(String msg, Object... params)2091 private void logIncoming(String msg, Object... params) { 2092 // Keep these as debug; the incoming logging is traced on a package level through the 2093 // session logging. 2094 Log.d(this, "CS -> TC[" + Log.getPackageAbbreviation(mComponentName) + "]: " 2095 + msg, params); 2096 } 2097 logOutgoing(String msg, Object... params)2098 private void logOutgoing(String msg, Object... params) { 2099 Log.d(this, "TC -> CS[" + Log.getPackageAbbreviation(mComponentName) + "]: " 2100 + msg, params); 2101 } 2102 queryRemoteConnectionServices(final UserHandle userHandle, final String callingPackage, final RemoteServiceCallback callback)2103 private void queryRemoteConnectionServices(final UserHandle userHandle, 2104 final String callingPackage, final RemoteServiceCallback callback) { 2105 boolean isCallerConnectionManager = false; 2106 // For each Sim ConnectionService, use its subid to find the correct connection manager for 2107 // that ConnectionService; return those Sim ConnectionServices which match the connection 2108 // manager. 2109 final Set<ConnectionServiceWrapper> simServices = Collections.newSetFromMap( 2110 new ConcurrentHashMap<ConnectionServiceWrapper, Boolean>(8, 0.9f, 1)); 2111 for (PhoneAccountHandle handle : mPhoneAccountRegistrar.getSimPhoneAccounts(userHandle)) { 2112 int subId = mPhoneAccountRegistrar.getSubscriptionIdForPhoneAccount(handle); 2113 PhoneAccountHandle connectionMgrHandle = mPhoneAccountRegistrar.getSimCallManager(subId, 2114 userHandle); 2115 if (connectionMgrHandle == null 2116 || !connectionMgrHandle.getComponentName().getPackageName().equals( 2117 callingPackage)) { 2118 Log.v(this, "queryRemoteConnectionServices: callingPackage=%s skipped; " 2119 + "doesn't match mgr %s for tfa %s", 2120 callingPackage, connectionMgrHandle, handle); 2121 } else { 2122 isCallerConnectionManager = true; 2123 } 2124 ConnectionServiceWrapper service = mConnectionServiceRepository.getService( 2125 handle.getComponentName(), handle.getUserHandle()); 2126 if (service != null && service != this) { 2127 simServices.add(service); 2128 } else { 2129 // This is unexpected, normally PhoneAccounts with CAPABILITY_CALL_PROVIDER are not 2130 // also CAPABILITY_CONNECTION_MANAGER 2131 Log.w(this, "call provider also detected as SIM call manager: " + service); 2132 } 2133 } 2134 2135 // Bail early if the caller isn't the sim connection mgr. 2136 if (!isCallerConnectionManager) { 2137 Log.d(this, "queryRemoteConnectionServices: none; not sim call mgr."); 2138 noRemoteServices(callback); 2139 return; 2140 } 2141 2142 final List<ComponentName> simServiceComponentNames = new ArrayList<>(); 2143 final List<IBinder> simServiceBinders = new ArrayList<>(); 2144 2145 Log.i(this, "queryRemoteConnectionServices, simServices = %s", simServices); 2146 2147 for (ConnectionServiceWrapper simService : simServices) { 2148 final ConnectionServiceWrapper currentSimService = simService; 2149 2150 currentSimService.mBinder.bind(new BindCallback() { 2151 @Override 2152 public void onSuccess() { 2153 Log.d(this, "queryRemoteConnectionServices: Adding simService %s", 2154 currentSimService.getComponentName()); 2155 if (currentSimService.mServiceInterface == null) { 2156 // The remote ConnectionService died, so do not add it. 2157 // We will still perform maybeComplete() and notify the caller with an empty 2158 // list of sim services via maybeComplete(). 2159 Log.w(this, "queryRemoteConnectionServices: simService %s died - Skipping.", 2160 currentSimService.getComponentName()); 2161 } else { 2162 simServiceComponentNames.add(currentSimService.getComponentName()); 2163 simServiceBinders.add(currentSimService.mServiceInterface.asBinder()); 2164 } 2165 maybeComplete(); 2166 } 2167 2168 @Override 2169 public void onFailure() { 2170 Log.d(this, "queryRemoteConnectionServices: Failed simService %s", 2171 currentSimService.getComponentName()); 2172 // We know maybeComplete() will always be a no-op from now on, so go ahead and 2173 // signal failure of the entire request 2174 noRemoteServices(callback); 2175 } 2176 2177 private void maybeComplete() { 2178 if (simServiceComponentNames.size() == simServices.size()) { 2179 setRemoteServices(callback, simServiceComponentNames, simServiceBinders); 2180 } 2181 } 2182 }, null); 2183 } 2184 } 2185 setRemoteServices( RemoteServiceCallback callback, List<ComponentName> componentNames, List<IBinder> binders)2186 private void setRemoteServices( 2187 RemoteServiceCallback callback, 2188 List<ComponentName> componentNames, 2189 List<IBinder> binders) { 2190 try { 2191 callback.onResult(componentNames, binders); 2192 } catch (RemoteException e) { 2193 Log.e(this, e, "setRemoteServices: Contacting ConnectionService %s", 2194 ConnectionServiceWrapper.this.getComponentName()); 2195 } 2196 } 2197 noRemoteServices(RemoteServiceCallback callback)2198 private void noRemoteServices(RemoteServiceCallback callback) { 2199 setRemoteServices(callback, Collections.EMPTY_LIST, Collections.EMPTY_LIST); 2200 } 2201 2202 @Override toString()2203 public String toString() { 2204 StringBuilder sb = new StringBuilder(); 2205 sb.append("[ConnectionServiceWrapper componentName="); 2206 sb.append(mComponentName); 2207 sb.append("]"); 2208 return sb.toString(); 2209 } 2210 } 2211