ConnectionService.java revision 0a88f2e21b3e3ed8a3a953e572a1eea6b572cb3e
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.telecom; 18 19import android.annotation.SdkConstant; 20import android.app.Service; 21import android.content.ComponentName; 22import android.content.Intent; 23import android.net.Uri; 24import android.os.Bundle; 25import android.os.Handler; 26import android.os.IBinder; 27import android.os.Looper; 28import android.os.Message; 29import android.os.ParcelFileDescriptor; 30import android.os.RemoteException; 31import android.telecom.Logging.Session; 32 33import com.android.internal.os.SomeArgs; 34import com.android.internal.telecom.IConnectionService; 35import com.android.internal.telecom.IConnectionServiceAdapter; 36import com.android.internal.telecom.RemoteServiceCallback; 37 38import java.util.ArrayList; 39import java.util.Collection; 40import java.util.Collections; 41import java.util.List; 42import java.util.Map; 43import java.util.UUID; 44import java.util.concurrent.ConcurrentHashMap; 45 46/** 47 * An abstract service that should be implemented by any apps which either: 48 * <ol> 49 * <li>Can make phone calls (VoIP or otherwise) and want those calls to be integrated into the 50 * built-in phone app. Referred to as a <b>system managed</b> {@link ConnectionService}.</li> 51 * <li>Are a standalone calling app and don't want their calls to be integrated into the 52 * built-in phone app. Referred to as a <b>self managed</b> {@link ConnectionService}.</li> 53 * </ol> 54 * Once implemented, the {@link ConnectionService} needs to take the following steps so that Telecom 55 * will bind to it: 56 * <p> 57 * 1. <i>Registration in AndroidManifest.xml</i> 58 * <br/> 59 * <pre> 60 * <service android:name="com.example.package.MyConnectionService" 61 * android:label="@string/some_label_for_my_connection_service" 62 * android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"> 63 * <intent-filter> 64 * <action android:name="android.telecom.ConnectionService" /> 65 * </intent-filter> 66 * </service> 67 * </pre> 68 * <p> 69 * 2. <i> Registration of {@link PhoneAccount} with {@link TelecomManager}.</i> 70 * <br/> 71 * See {@link PhoneAccount} and {@link TelecomManager#registerPhoneAccount} for more information. 72 * <p> 73 * System managed {@link ConnectionService}s must be enabled by the user in the phone app settings 74 * before Telecom will bind to them. Self-manged {@link ConnectionService}s must be granted the 75 * appropriate permission before Telecom will bind to them. 76 * <p> 77 * Once registered and enabled by the user in the phone app settings or granted permission, telecom 78 * will bind to a {@link ConnectionService} implementation when it wants that 79 * {@link ConnectionService} to place a call or the service has indicated that is has an incoming 80 * call through {@link TelecomManager#addNewIncomingCall}. The {@link ConnectionService} can then 81 * expect a call to {@link #onCreateIncomingConnection} or {@link #onCreateOutgoingConnection} 82 * wherein it should provide a new instance of a {@link Connection} object. It is through this 83 * {@link Connection} object that telecom receives state updates and the {@link ConnectionService} 84 * receives call-commands such as answer, reject, hold and disconnect. 85 * <p> 86 * When there are no more live calls, telecom will unbind from the {@link ConnectionService}. 87 */ 88public abstract class ConnectionService extends Service { 89 /** 90 * The {@link Intent} that must be declared as handled by the service. 91 */ 92 @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) 93 public static final String SERVICE_INTERFACE = "android.telecom.ConnectionService"; 94 95 /** 96 * Boolean extra used by Telecom to inform a {@link ConnectionService} that the purpose of it 97 * being asked to create a new outgoing {@link Connection} is to perform a handover of an 98 * ongoing call on the device from another {@link PhoneAccount}/{@link ConnectionService}. Will 99 * be specified in the {@link ConnectionRequest#getExtras()} passed by Telecom when 100 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)} is called. 101 * <p> 102 * When your {@link ConnectionService} receives this extra, it should communicate the fact that 103 * this is a handover to the other device's matching {@link ConnectionService}. That 104 * {@link ConnectionService} will continue the handover using 105 * {@link TelecomManager#addNewIncomingCall(PhoneAccountHandle, Bundle)}, specifying 106 * {@link TelecomManager#EXTRA_IS_HANDOVER}. Telecom will match the phone numbers of the 107 * handover call on the other device with ongoing calls for {@link ConnectionService}s which 108 * support {@link PhoneAccount#EXTRA_SUPPORTS_HANDOVER_FROM}. 109 * @hide 110 */ 111 public static final String EXTRA_IS_HANDOVER = TelecomManager.EXTRA_IS_HANDOVER; 112 113 // Flag controlling whether PII is emitted into the logs 114 private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG); 115 116 // Session Definitions 117 private static final String SESSION_HANDLER = "H."; 118 private static final String SESSION_ADD_CS_ADAPTER = "CS.aCSA"; 119 private static final String SESSION_REMOVE_CS_ADAPTER = "CS.rCSA"; 120 private static final String SESSION_CREATE_CONN = "CS.crCo"; 121 private static final String SESSION_CREATE_CONN_COMPLETE = "CS.crCoC"; 122 private static final String SESSION_CREATE_CONN_FAILED = "CS.crCoF"; 123 private static final String SESSION_ABORT = "CS.ab"; 124 private static final String SESSION_ANSWER = "CS.an"; 125 private static final String SESSION_ANSWER_VIDEO = "CS.anV"; 126 private static final String SESSION_REJECT = "CS.r"; 127 private static final String SESSION_REJECT_MESSAGE = "CS.rWM"; 128 private static final String SESSION_SILENCE = "CS.s"; 129 private static final String SESSION_DISCONNECT = "CS.d"; 130 private static final String SESSION_HOLD = "CS.h"; 131 private static final String SESSION_UNHOLD = "CS.u"; 132 private static final String SESSION_CALL_AUDIO_SC = "CS.cASC"; 133 private static final String SESSION_PLAY_DTMF = "CS.pDT"; 134 private static final String SESSION_STOP_DTMF = "CS.sDT"; 135 private static final String SESSION_CONFERENCE = "CS.c"; 136 private static final String SESSION_SPLIT_CONFERENCE = "CS.sFC"; 137 private static final String SESSION_MERGE_CONFERENCE = "CS.mC"; 138 private static final String SESSION_SWAP_CONFERENCE = "CS.sC"; 139 private static final String SESSION_POST_DIAL_CONT = "CS.oPDC"; 140 private static final String SESSION_PULL_EXTERNAL_CALL = "CS.pEC"; 141 private static final String SESSION_SEND_CALL_EVENT = "CS.sCE"; 142 private static final String SESSION_EXTRAS_CHANGED = "CS.oEC"; 143 private static final String SESSION_START_RTT = "CS.+RTT"; 144 private static final String SESSION_STOP_RTT = "CS.-RTT"; 145 private static final String SESSION_RTT_UPGRADE_RESPONSE = "CS.rTRUR"; 146 147 private static final int MSG_ADD_CONNECTION_SERVICE_ADAPTER = 1; 148 private static final int MSG_CREATE_CONNECTION = 2; 149 private static final int MSG_ABORT = 3; 150 private static final int MSG_ANSWER = 4; 151 private static final int MSG_REJECT = 5; 152 private static final int MSG_DISCONNECT = 6; 153 private static final int MSG_HOLD = 7; 154 private static final int MSG_UNHOLD = 8; 155 private static final int MSG_ON_CALL_AUDIO_STATE_CHANGED = 9; 156 private static final int MSG_PLAY_DTMF_TONE = 10; 157 private static final int MSG_STOP_DTMF_TONE = 11; 158 private static final int MSG_CONFERENCE = 12; 159 private static final int MSG_SPLIT_FROM_CONFERENCE = 13; 160 private static final int MSG_ON_POST_DIAL_CONTINUE = 14; 161 private static final int MSG_REMOVE_CONNECTION_SERVICE_ADAPTER = 16; 162 private static final int MSG_ANSWER_VIDEO = 17; 163 private static final int MSG_MERGE_CONFERENCE = 18; 164 private static final int MSG_SWAP_CONFERENCE = 19; 165 private static final int MSG_REJECT_WITH_MESSAGE = 20; 166 private static final int MSG_SILENCE = 21; 167 private static final int MSG_PULL_EXTERNAL_CALL = 22; 168 private static final int MSG_SEND_CALL_EVENT = 23; 169 private static final int MSG_ON_EXTRAS_CHANGED = 24; 170 private static final int MSG_CREATE_CONNECTION_FAILED = 25; 171 private static final int MSG_ON_START_RTT = 26; 172 private static final int MSG_ON_STOP_RTT = 27; 173 private static final int MSG_RTT_UPGRADE_RESPONSE = 28; 174 private static final int MSG_CREATE_CONNECTION_COMPLETE = 29; 175 176 private static Connection sNullConnection; 177 178 private final Map<String, Connection> mConnectionById = new ConcurrentHashMap<>(); 179 private final Map<Connection, String> mIdByConnection = new ConcurrentHashMap<>(); 180 private final Map<String, Conference> mConferenceById = new ConcurrentHashMap<>(); 181 private final Map<Conference, String> mIdByConference = new ConcurrentHashMap<>(); 182 private final RemoteConnectionManager mRemoteConnectionManager = 183 new RemoteConnectionManager(this); 184 private final List<Runnable> mPreInitializationConnectionRequests = new ArrayList<>(); 185 private final ConnectionServiceAdapter mAdapter = new ConnectionServiceAdapter(); 186 187 private boolean mAreAccountsInitialized = false; 188 private Conference sNullConference; 189 private Object mIdSyncRoot = new Object(); 190 private int mId = 0; 191 192 private final IBinder mBinder = new IConnectionService.Stub() { 193 @Override 194 public void addConnectionServiceAdapter(IConnectionServiceAdapter adapter, 195 Session.Info sessionInfo) { 196 Log.startSession(sessionInfo, SESSION_ADD_CS_ADAPTER); 197 try { 198 SomeArgs args = SomeArgs.obtain(); 199 args.arg1 = adapter; 200 args.arg2 = Log.createSubsession(); 201 mHandler.obtainMessage(MSG_ADD_CONNECTION_SERVICE_ADAPTER, args).sendToTarget(); 202 } finally { 203 Log.endSession(); 204 } 205 } 206 207 public void removeConnectionServiceAdapter(IConnectionServiceAdapter adapter, 208 Session.Info sessionInfo) { 209 Log.startSession(sessionInfo, SESSION_REMOVE_CS_ADAPTER); 210 try { 211 SomeArgs args = SomeArgs.obtain(); 212 args.arg1 = adapter; 213 args.arg2 = Log.createSubsession(); 214 mHandler.obtainMessage(MSG_REMOVE_CONNECTION_SERVICE_ADAPTER, args).sendToTarget(); 215 } finally { 216 Log.endSession(); 217 } 218 } 219 220 @Override 221 public void createConnection( 222 PhoneAccountHandle connectionManagerPhoneAccount, 223 String id, 224 ConnectionRequest request, 225 boolean isIncoming, 226 boolean isUnknown, 227 Session.Info sessionInfo) { 228 Log.startSession(sessionInfo, SESSION_CREATE_CONN); 229 try { 230 SomeArgs args = SomeArgs.obtain(); 231 args.arg1 = connectionManagerPhoneAccount; 232 args.arg2 = id; 233 args.arg3 = request; 234 args.arg4 = Log.createSubsession(); 235 args.argi1 = isIncoming ? 1 : 0; 236 args.argi2 = isUnknown ? 1 : 0; 237 mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget(); 238 } finally { 239 Log.endSession(); 240 } 241 } 242 243 @Override 244 public void createConnectionComplete(String id, Session.Info sessionInfo) { 245 Log.startSession(sessionInfo, SESSION_CREATE_CONN_COMPLETE); 246 try { 247 SomeArgs args = SomeArgs.obtain(); 248 args.arg1 = id; 249 args.arg2 = Log.createSubsession(); 250 mHandler.obtainMessage(MSG_CREATE_CONNECTION_COMPLETE, args).sendToTarget(); 251 } finally { 252 Log.endSession(); 253 } 254 } 255 256 @Override 257 public void createConnectionFailed( 258 PhoneAccountHandle connectionManagerPhoneAccount, 259 String callId, 260 ConnectionRequest request, 261 boolean isIncoming, 262 Session.Info sessionInfo) { 263 Log.startSession(sessionInfo, SESSION_CREATE_CONN_FAILED); 264 try { 265 SomeArgs args = SomeArgs.obtain(); 266 args.arg1 = callId; 267 args.arg2 = request; 268 args.arg3 = Log.createSubsession(); 269 args.arg4 = connectionManagerPhoneAccount; 270 args.argi1 = isIncoming ? 1 : 0; 271 mHandler.obtainMessage(MSG_CREATE_CONNECTION_FAILED, args).sendToTarget(); 272 } finally { 273 Log.endSession(); 274 } 275 } 276 277 @Override 278 public void abort(String callId, Session.Info sessionInfo) { 279 Log.startSession(sessionInfo, SESSION_ABORT); 280 try { 281 SomeArgs args = SomeArgs.obtain(); 282 args.arg1 = callId; 283 args.arg2 = Log.createSubsession(); 284 mHandler.obtainMessage(MSG_ABORT, args).sendToTarget(); 285 } finally { 286 Log.endSession(); 287 } 288 } 289 290 @Override 291 public void answerVideo(String callId, int videoState, Session.Info sessionInfo) { 292 Log.startSession(sessionInfo, SESSION_ANSWER_VIDEO); 293 try { 294 SomeArgs args = SomeArgs.obtain(); 295 args.arg1 = callId; 296 args.arg2 = Log.createSubsession(); 297 args.argi1 = videoState; 298 mHandler.obtainMessage(MSG_ANSWER_VIDEO, args).sendToTarget(); 299 } finally { 300 Log.endSession(); 301 } 302 } 303 304 @Override 305 public void answer(String callId, Session.Info sessionInfo) { 306 Log.startSession(sessionInfo, SESSION_ANSWER); 307 try { 308 SomeArgs args = SomeArgs.obtain(); 309 args.arg1 = callId; 310 args.arg2 = Log.createSubsession(); 311 mHandler.obtainMessage(MSG_ANSWER, args).sendToTarget(); 312 } finally { 313 Log.endSession(); 314 } 315 } 316 317 @Override 318 public void reject(String callId, Session.Info sessionInfo) { 319 Log.startSession(sessionInfo, SESSION_REJECT); 320 try { 321 SomeArgs args = SomeArgs.obtain(); 322 args.arg1 = callId; 323 args.arg2 = Log.createSubsession(); 324 mHandler.obtainMessage(MSG_REJECT, args).sendToTarget(); 325 } finally { 326 Log.endSession(); 327 } 328 } 329 330 @Override 331 public void rejectWithMessage(String callId, String message, Session.Info sessionInfo) { 332 Log.startSession(sessionInfo, SESSION_REJECT_MESSAGE); 333 try { 334 SomeArgs args = SomeArgs.obtain(); 335 args.arg1 = callId; 336 args.arg2 = message; 337 args.arg3 = Log.createSubsession(); 338 mHandler.obtainMessage(MSG_REJECT_WITH_MESSAGE, args).sendToTarget(); 339 } finally { 340 Log.endSession(); 341 } 342 } 343 344 @Override 345 public void silence(String callId, Session.Info sessionInfo) { 346 Log.startSession(sessionInfo, SESSION_SILENCE); 347 try { 348 SomeArgs args = SomeArgs.obtain(); 349 args.arg1 = callId; 350 args.arg2 = Log.createSubsession(); 351 mHandler.obtainMessage(MSG_SILENCE, args).sendToTarget(); 352 } finally { 353 Log.endSession(); 354 } 355 } 356 357 @Override 358 public void disconnect(String callId, Session.Info sessionInfo) { 359 Log.startSession(sessionInfo, SESSION_DISCONNECT); 360 try { 361 SomeArgs args = SomeArgs.obtain(); 362 args.arg1 = callId; 363 args.arg2 = Log.createSubsession(); 364 mHandler.obtainMessage(MSG_DISCONNECT, args).sendToTarget(); 365 } finally { 366 Log.endSession(); 367 } 368 } 369 370 @Override 371 public void hold(String callId, Session.Info sessionInfo) { 372 Log.startSession(sessionInfo, SESSION_HOLD); 373 try { 374 SomeArgs args = SomeArgs.obtain(); 375 args.arg1 = callId; 376 args.arg2 = Log.createSubsession(); 377 mHandler.obtainMessage(MSG_HOLD, args).sendToTarget(); 378 } finally { 379 Log.endSession(); 380 } 381 } 382 383 @Override 384 public void unhold(String callId, Session.Info sessionInfo) { 385 Log.startSession(sessionInfo, SESSION_UNHOLD); 386 try { 387 SomeArgs args = SomeArgs.obtain(); 388 args.arg1 = callId; 389 args.arg2 = Log.createSubsession(); 390 mHandler.obtainMessage(MSG_UNHOLD, args).sendToTarget(); 391 } finally { 392 Log.endSession(); 393 } 394 } 395 396 @Override 397 public void onCallAudioStateChanged(String callId, CallAudioState callAudioState, 398 Session.Info sessionInfo) { 399 Log.startSession(sessionInfo, SESSION_CALL_AUDIO_SC); 400 try { 401 SomeArgs args = SomeArgs.obtain(); 402 args.arg1 = callId; 403 args.arg2 = callAudioState; 404 args.arg3 = Log.createSubsession(); 405 mHandler.obtainMessage(MSG_ON_CALL_AUDIO_STATE_CHANGED, args).sendToTarget(); 406 } finally { 407 Log.endSession(); 408 } 409 } 410 411 @Override 412 public void playDtmfTone(String callId, char digit, Session.Info sessionInfo) { 413 Log.startSession(sessionInfo, SESSION_PLAY_DTMF); 414 try { 415 SomeArgs args = SomeArgs.obtain(); 416 args.arg1 = digit; 417 args.arg2 = callId; 418 args.arg3 = Log.createSubsession(); 419 mHandler.obtainMessage(MSG_PLAY_DTMF_TONE, args).sendToTarget(); 420 } finally { 421 Log.endSession(); 422 } 423 } 424 425 @Override 426 public void stopDtmfTone(String callId, Session.Info sessionInfo) { 427 Log.startSession(sessionInfo, SESSION_STOP_DTMF); 428 try { 429 SomeArgs args = SomeArgs.obtain(); 430 args.arg1 = callId; 431 args.arg2 = Log.createSubsession(); 432 mHandler.obtainMessage(MSG_STOP_DTMF_TONE, args).sendToTarget(); 433 } finally { 434 Log.endSession(); 435 } 436 } 437 438 @Override 439 public void conference(String callId1, String callId2, Session.Info sessionInfo) { 440 Log.startSession(sessionInfo, SESSION_CONFERENCE); 441 try { 442 SomeArgs args = SomeArgs.obtain(); 443 args.arg1 = callId1; 444 args.arg2 = callId2; 445 args.arg3 = Log.createSubsession(); 446 mHandler.obtainMessage(MSG_CONFERENCE, args).sendToTarget(); 447 } finally { 448 Log.endSession(); 449 } 450 } 451 452 @Override 453 public void splitFromConference(String callId, Session.Info sessionInfo) { 454 Log.startSession(sessionInfo, SESSION_SPLIT_CONFERENCE); 455 try { 456 SomeArgs args = SomeArgs.obtain(); 457 args.arg1 = callId; 458 args.arg2 = Log.createSubsession(); 459 mHandler.obtainMessage(MSG_SPLIT_FROM_CONFERENCE, args).sendToTarget(); 460 } finally { 461 Log.endSession(); 462 } 463 } 464 465 @Override 466 public void mergeConference(String callId, Session.Info sessionInfo) { 467 Log.startSession(sessionInfo, SESSION_MERGE_CONFERENCE); 468 try { 469 SomeArgs args = SomeArgs.obtain(); 470 args.arg1 = callId; 471 args.arg2 = Log.createSubsession(); 472 mHandler.obtainMessage(MSG_MERGE_CONFERENCE, args).sendToTarget(); 473 } finally { 474 Log.endSession(); 475 } 476 } 477 478 @Override 479 public void swapConference(String callId, Session.Info sessionInfo) { 480 Log.startSession(sessionInfo, SESSION_SWAP_CONFERENCE); 481 try { 482 SomeArgs args = SomeArgs.obtain(); 483 args.arg1 = callId; 484 args.arg2 = Log.createSubsession(); 485 mHandler.obtainMessage(MSG_SWAP_CONFERENCE, args).sendToTarget(); 486 } finally { 487 Log.endSession(); 488 } 489 } 490 491 @Override 492 public void onPostDialContinue(String callId, boolean proceed, Session.Info sessionInfo) { 493 Log.startSession(sessionInfo, SESSION_POST_DIAL_CONT); 494 try { 495 SomeArgs args = SomeArgs.obtain(); 496 args.arg1 = callId; 497 args.arg2 = Log.createSubsession(); 498 args.argi1 = proceed ? 1 : 0; 499 mHandler.obtainMessage(MSG_ON_POST_DIAL_CONTINUE, args).sendToTarget(); 500 } finally { 501 Log.endSession(); 502 } 503 } 504 505 @Override 506 public void pullExternalCall(String callId, Session.Info sessionInfo) { 507 Log.startSession(sessionInfo, SESSION_PULL_EXTERNAL_CALL); 508 try { 509 SomeArgs args = SomeArgs.obtain(); 510 args.arg1 = callId; 511 args.arg2 = Log.createSubsession(); 512 mHandler.obtainMessage(MSG_PULL_EXTERNAL_CALL, args).sendToTarget(); 513 } finally { 514 Log.endSession(); 515 } 516 } 517 518 @Override 519 public void sendCallEvent(String callId, String event, Bundle extras, 520 Session.Info sessionInfo) { 521 Log.startSession(sessionInfo, SESSION_SEND_CALL_EVENT); 522 try { 523 SomeArgs args = SomeArgs.obtain(); 524 args.arg1 = callId; 525 args.arg2 = event; 526 args.arg3 = extras; 527 args.arg4 = Log.createSubsession(); 528 mHandler.obtainMessage(MSG_SEND_CALL_EVENT, args).sendToTarget(); 529 } finally { 530 Log.endSession(); 531 } 532 } 533 534 @Override 535 public void onExtrasChanged(String callId, Bundle extras, Session.Info sessionInfo) { 536 Log.startSession(sessionInfo, SESSION_EXTRAS_CHANGED); 537 try { 538 SomeArgs args = SomeArgs.obtain(); 539 args.arg1 = callId; 540 args.arg2 = extras; 541 args.arg3 = Log.createSubsession(); 542 mHandler.obtainMessage(MSG_ON_EXTRAS_CHANGED, args).sendToTarget(); 543 } finally { 544 Log.endSession(); 545 } 546 } 547 548 @Override 549 public void startRtt(String callId, ParcelFileDescriptor fromInCall, 550 ParcelFileDescriptor toInCall, Session.Info sessionInfo) throws RemoteException { 551 Log.startSession(sessionInfo, SESSION_START_RTT); 552 try { 553 SomeArgs args = SomeArgs.obtain(); 554 args.arg1 = callId; 555 args.arg2 = new Connection.RttTextStream(toInCall, fromInCall); 556 args.arg3 = Log.createSubsession(); 557 mHandler.obtainMessage(MSG_ON_START_RTT, args).sendToTarget(); 558 } finally { 559 Log.endSession(); 560 } 561 } 562 563 @Override 564 public void stopRtt(String callId, Session.Info sessionInfo) throws RemoteException { 565 Log.startSession(sessionInfo, SESSION_STOP_RTT); 566 try { 567 SomeArgs args = SomeArgs.obtain(); 568 args.arg1 = callId; 569 args.arg2 = Log.createSubsession(); 570 mHandler.obtainMessage(MSG_ON_STOP_RTT, args).sendToTarget(); 571 } finally { 572 Log.endSession(); 573 } 574 } 575 576 @Override 577 public void respondToRttUpgradeRequest(String callId, ParcelFileDescriptor fromInCall, 578 ParcelFileDescriptor toInCall, Session.Info sessionInfo) throws RemoteException { 579 Log.startSession(sessionInfo, SESSION_RTT_UPGRADE_RESPONSE); 580 try { 581 SomeArgs args = SomeArgs.obtain(); 582 args.arg1 = callId; 583 if (toInCall == null || fromInCall == null) { 584 args.arg2 = null; 585 } else { 586 args.arg2 = new Connection.RttTextStream(toInCall, fromInCall); 587 } 588 args.arg3 = Log.createSubsession(); 589 mHandler.obtainMessage(MSG_RTT_UPGRADE_RESPONSE, args).sendToTarget(); 590 } finally { 591 Log.endSession(); 592 } 593 } 594 }; 595 596 private final Handler mHandler = new Handler(Looper.getMainLooper()) { 597 @Override 598 public void handleMessage(Message msg) { 599 switch (msg.what) { 600 case MSG_ADD_CONNECTION_SERVICE_ADAPTER: { 601 SomeArgs args = (SomeArgs) msg.obj; 602 try { 603 IConnectionServiceAdapter adapter = (IConnectionServiceAdapter) args.arg1; 604 Log.continueSession((Session) args.arg2, 605 SESSION_HANDLER + SESSION_ADD_CS_ADAPTER); 606 mAdapter.addAdapter(adapter); 607 onAdapterAttached(); 608 } finally { 609 args.recycle(); 610 Log.endSession(); 611 } 612 break; 613 } 614 case MSG_REMOVE_CONNECTION_SERVICE_ADAPTER: { 615 SomeArgs args = (SomeArgs) msg.obj; 616 try { 617 Log.continueSession((Session) args.arg2, 618 SESSION_HANDLER + SESSION_REMOVE_CS_ADAPTER); 619 mAdapter.removeAdapter((IConnectionServiceAdapter) args.arg1); 620 } finally { 621 args.recycle(); 622 Log.endSession(); 623 } 624 break; 625 } 626 case MSG_CREATE_CONNECTION: { 627 SomeArgs args = (SomeArgs) msg.obj; 628 Log.continueSession((Session) args.arg4, SESSION_HANDLER + SESSION_CREATE_CONN); 629 try { 630 final PhoneAccountHandle connectionManagerPhoneAccount = 631 (PhoneAccountHandle) args.arg1; 632 final String id = (String) args.arg2; 633 final ConnectionRequest request = (ConnectionRequest) args.arg3; 634 final boolean isIncoming = args.argi1 == 1; 635 final boolean isUnknown = args.argi2 == 1; 636 if (!mAreAccountsInitialized) { 637 Log.d(this, "Enqueueing pre-init request %s", id); 638 mPreInitializationConnectionRequests.add( 639 new android.telecom.Logging.Runnable( 640 SESSION_HANDLER + SESSION_CREATE_CONN + ".pICR", 641 null /*lock*/) { 642 @Override 643 public void loggedRun() { 644 createConnection( 645 connectionManagerPhoneAccount, 646 id, 647 request, 648 isIncoming, 649 isUnknown); 650 } 651 }.prepare()); 652 } else { 653 createConnection( 654 connectionManagerPhoneAccount, 655 id, 656 request, 657 isIncoming, 658 isUnknown); 659 } 660 } finally { 661 args.recycle(); 662 Log.endSession(); 663 } 664 break; 665 } 666 case MSG_CREATE_CONNECTION_COMPLETE: { 667 SomeArgs args = (SomeArgs) msg.obj; 668 Log.continueSession((Session) args.arg2, 669 SESSION_HANDLER + SESSION_CREATE_CONN_COMPLETE); 670 try { 671 final String id = (String) args.arg1; 672 if (!mAreAccountsInitialized) { 673 Log.d(this, "Enqueueing pre-init request %s", id); 674 mPreInitializationConnectionRequests.add( 675 new android.telecom.Logging.Runnable( 676 SESSION_HANDLER + SESSION_CREATE_CONN_COMPLETE 677 + ".pICR", 678 null /*lock*/) { 679 @Override 680 public void loggedRun() { 681 notifyCreateConnectionComplete(id); 682 } 683 }.prepare()); 684 } else { 685 notifyCreateConnectionComplete(id); 686 } 687 } finally { 688 args.recycle(); 689 Log.endSession(); 690 } 691 break; 692 } 693 case MSG_CREATE_CONNECTION_FAILED: { 694 SomeArgs args = (SomeArgs) msg.obj; 695 Log.continueSession((Session) args.arg3, SESSION_HANDLER + 696 SESSION_CREATE_CONN_FAILED); 697 try { 698 final String id = (String) args.arg1; 699 final ConnectionRequest request = (ConnectionRequest) args.arg2; 700 final boolean isIncoming = args.argi1 == 1; 701 final PhoneAccountHandle connectionMgrPhoneAccount = 702 (PhoneAccountHandle) args.arg4; 703 if (!mAreAccountsInitialized) { 704 Log.d(this, "Enqueueing pre-init request %s", id); 705 mPreInitializationConnectionRequests.add( 706 new android.telecom.Logging.Runnable( 707 SESSION_HANDLER + SESSION_CREATE_CONN_FAILED + ".pICR", 708 null /*lock*/) { 709 @Override 710 public void loggedRun() { 711 createConnectionFailed(connectionMgrPhoneAccount, id, 712 request, isIncoming); 713 } 714 }.prepare()); 715 } else { 716 Log.i(this, "createConnectionFailed %s", id); 717 createConnectionFailed(connectionMgrPhoneAccount, id, request, 718 isIncoming); 719 } 720 } finally { 721 args.recycle(); 722 Log.endSession(); 723 } 724 break; 725 } 726 case MSG_ABORT: { 727 SomeArgs args = (SomeArgs) msg.obj; 728 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_ABORT); 729 try { 730 abort((String) args.arg1); 731 } finally { 732 args.recycle(); 733 Log.endSession(); 734 } 735 break; 736 } 737 case MSG_ANSWER: { 738 SomeArgs args = (SomeArgs) msg.obj; 739 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_ANSWER); 740 try { 741 answer((String) args.arg1); 742 } finally { 743 args.recycle(); 744 Log.endSession(); 745 } 746 break; 747 } 748 case MSG_ANSWER_VIDEO: { 749 SomeArgs args = (SomeArgs) msg.obj; 750 Log.continueSession((Session) args.arg2, 751 SESSION_HANDLER + SESSION_ANSWER_VIDEO); 752 try { 753 String callId = (String) args.arg1; 754 int videoState = args.argi1; 755 answerVideo(callId, videoState); 756 } finally { 757 args.recycle(); 758 Log.endSession(); 759 } 760 break; 761 } 762 case MSG_REJECT: { 763 SomeArgs args = (SomeArgs) msg.obj; 764 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_REJECT); 765 try { 766 reject((String) args.arg1); 767 } finally { 768 args.recycle(); 769 Log.endSession(); 770 } 771 break; 772 } 773 case MSG_REJECT_WITH_MESSAGE: { 774 SomeArgs args = (SomeArgs) msg.obj; 775 Log.continueSession((Session) args.arg3, 776 SESSION_HANDLER + SESSION_REJECT_MESSAGE); 777 try { 778 reject((String) args.arg1, (String) args.arg2); 779 } finally { 780 args.recycle(); 781 Log.endSession(); 782 } 783 break; 784 } 785 case MSG_DISCONNECT: { 786 SomeArgs args = (SomeArgs) msg.obj; 787 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_DISCONNECT); 788 try { 789 disconnect((String) args.arg1); 790 } finally { 791 args.recycle(); 792 Log.endSession(); 793 } 794 break; 795 } 796 case MSG_SILENCE: { 797 SomeArgs args = (SomeArgs) msg.obj; 798 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_SILENCE); 799 try { 800 silence((String) args.arg1); 801 } finally { 802 args.recycle(); 803 Log.endSession(); 804 } 805 break; 806 } 807 case MSG_HOLD: { 808 SomeArgs args = (SomeArgs) msg.obj; 809 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_REJECT); 810 try { 811 hold((String) args.arg1); 812 } finally { 813 args.recycle(); 814 Log.endSession(); 815 } 816 break; 817 } 818 case MSG_UNHOLD: { 819 SomeArgs args = (SomeArgs) msg.obj; 820 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_UNHOLD); 821 try { 822 unhold((String) args.arg1); 823 } finally { 824 args.recycle(); 825 Log.endSession(); 826 } 827 break; 828 } 829 case MSG_ON_CALL_AUDIO_STATE_CHANGED: { 830 SomeArgs args = (SomeArgs) msg.obj; 831 Log.continueSession((Session) args.arg3, 832 SESSION_HANDLER + SESSION_CALL_AUDIO_SC); 833 try { 834 String callId = (String) args.arg1; 835 CallAudioState audioState = (CallAudioState) args.arg2; 836 onCallAudioStateChanged(callId, new CallAudioState(audioState)); 837 } finally { 838 args.recycle(); 839 Log.endSession(); 840 } 841 break; 842 } 843 case MSG_PLAY_DTMF_TONE: { 844 SomeArgs args = (SomeArgs) msg.obj; 845 try { 846 Log.continueSession((Session) args.arg3, 847 SESSION_HANDLER + SESSION_PLAY_DTMF); 848 playDtmfTone((String) args.arg2, (char) args.arg1); 849 } finally { 850 args.recycle(); 851 Log.endSession(); 852 } 853 break; 854 } 855 case MSG_STOP_DTMF_TONE: { 856 SomeArgs args = (SomeArgs) msg.obj; 857 try { 858 Log.continueSession((Session) args.arg2, 859 SESSION_HANDLER + SESSION_STOP_DTMF); 860 stopDtmfTone((String) args.arg1); 861 } finally { 862 args.recycle(); 863 Log.endSession(); 864 } 865 break; 866 } 867 case MSG_CONFERENCE: { 868 SomeArgs args = (SomeArgs) msg.obj; 869 try { 870 Log.continueSession((Session) args.arg3, 871 SESSION_HANDLER + SESSION_CONFERENCE); 872 String callId1 = (String) args.arg1; 873 String callId2 = (String) args.arg2; 874 conference(callId1, callId2); 875 } finally { 876 args.recycle(); 877 Log.endSession(); 878 } 879 break; 880 } 881 case MSG_SPLIT_FROM_CONFERENCE: { 882 SomeArgs args = (SomeArgs) msg.obj; 883 try { 884 Log.continueSession((Session) args.arg2, 885 SESSION_HANDLER + SESSION_SPLIT_CONFERENCE); 886 splitFromConference((String) args.arg1); 887 } finally { 888 args.recycle(); 889 Log.endSession(); 890 } 891 break; 892 } 893 case MSG_MERGE_CONFERENCE: { 894 SomeArgs args = (SomeArgs) msg.obj; 895 try { 896 Log.continueSession((Session) args.arg2, 897 SESSION_HANDLER + SESSION_MERGE_CONFERENCE); 898 mergeConference((String) args.arg1); 899 } finally { 900 args.recycle(); 901 Log.endSession(); 902 } 903 break; 904 } 905 case MSG_SWAP_CONFERENCE: { 906 SomeArgs args = (SomeArgs) msg.obj; 907 try { 908 Log.continueSession((Session) args.arg2, 909 SESSION_HANDLER + SESSION_SWAP_CONFERENCE); 910 swapConference((String) args.arg1); 911 } finally { 912 args.recycle(); 913 Log.endSession(); 914 } 915 break; 916 } 917 case MSG_ON_POST_DIAL_CONTINUE: { 918 SomeArgs args = (SomeArgs) msg.obj; 919 try { 920 Log.continueSession((Session) args.arg2, 921 SESSION_HANDLER + SESSION_POST_DIAL_CONT); 922 String callId = (String) args.arg1; 923 boolean proceed = (args.argi1 == 1); 924 onPostDialContinue(callId, proceed); 925 } finally { 926 args.recycle(); 927 Log.endSession(); 928 } 929 break; 930 } 931 case MSG_PULL_EXTERNAL_CALL: { 932 SomeArgs args = (SomeArgs) msg.obj; 933 try { 934 Log.continueSession((Session) args.arg2, 935 SESSION_HANDLER + SESSION_PULL_EXTERNAL_CALL); 936 pullExternalCall((String) args.arg1); 937 } finally { 938 args.recycle(); 939 Log.endSession(); 940 } 941 break; 942 } 943 case MSG_SEND_CALL_EVENT: { 944 SomeArgs args = (SomeArgs) msg.obj; 945 try { 946 Log.continueSession((Session) args.arg4, 947 SESSION_HANDLER + SESSION_SEND_CALL_EVENT); 948 String callId = (String) args.arg1; 949 String event = (String) args.arg2; 950 Bundle extras = (Bundle) args.arg3; 951 sendCallEvent(callId, event, extras); 952 } finally { 953 args.recycle(); 954 Log.endSession(); 955 } 956 break; 957 } 958 case MSG_ON_EXTRAS_CHANGED: { 959 SomeArgs args = (SomeArgs) msg.obj; 960 try { 961 Log.continueSession((Session) args.arg3, 962 SESSION_HANDLER + SESSION_EXTRAS_CHANGED); 963 String callId = (String) args.arg1; 964 Bundle extras = (Bundle) args.arg2; 965 handleExtrasChanged(callId, extras); 966 } finally { 967 args.recycle(); 968 Log.endSession(); 969 } 970 break; 971 } 972 case MSG_ON_START_RTT: { 973 SomeArgs args = (SomeArgs) msg.obj; 974 try { 975 Log.continueSession((Session) args.arg3, 976 SESSION_HANDLER + SESSION_START_RTT); 977 String callId = (String) args.arg1; 978 Connection.RttTextStream rttTextStream = 979 (Connection.RttTextStream) args.arg2; 980 startRtt(callId, rttTextStream); 981 } finally { 982 args.recycle(); 983 Log.endSession(); 984 } 985 break; 986 } 987 case MSG_ON_STOP_RTT: { 988 SomeArgs args = (SomeArgs) msg.obj; 989 try { 990 Log.continueSession((Session) args.arg2, 991 SESSION_HANDLER + SESSION_STOP_RTT); 992 String callId = (String) args.arg1; 993 stopRtt(callId); 994 } finally { 995 args.recycle(); 996 Log.endSession(); 997 } 998 break; 999 } 1000 case MSG_RTT_UPGRADE_RESPONSE: { 1001 SomeArgs args = (SomeArgs) msg.obj; 1002 try { 1003 Log.continueSession((Session) args.arg3, 1004 SESSION_HANDLER + SESSION_RTT_UPGRADE_RESPONSE); 1005 String callId = (String) args.arg1; 1006 Connection.RttTextStream rttTextStream = 1007 (Connection.RttTextStream) args.arg2; 1008 handleRttUpgradeResponse(callId, rttTextStream); 1009 } finally { 1010 args.recycle(); 1011 Log.endSession(); 1012 } 1013 break; 1014 } 1015 default: 1016 break; 1017 } 1018 } 1019 }; 1020 1021 private final Conference.Listener mConferenceListener = new Conference.Listener() { 1022 @Override 1023 public void onStateChanged(Conference conference, int oldState, int newState) { 1024 String id = mIdByConference.get(conference); 1025 switch (newState) { 1026 case Connection.STATE_ACTIVE: 1027 mAdapter.setActive(id); 1028 break; 1029 case Connection.STATE_HOLDING: 1030 mAdapter.setOnHold(id); 1031 break; 1032 case Connection.STATE_DISCONNECTED: 1033 // handled by onDisconnected 1034 break; 1035 } 1036 } 1037 1038 @Override 1039 public void onDisconnected(Conference conference, DisconnectCause disconnectCause) { 1040 String id = mIdByConference.get(conference); 1041 mAdapter.setDisconnected(id, disconnectCause); 1042 } 1043 1044 @Override 1045 public void onConnectionAdded(Conference conference, Connection connection) { 1046 } 1047 1048 @Override 1049 public void onConnectionRemoved(Conference conference, Connection connection) { 1050 } 1051 1052 @Override 1053 public void onConferenceableConnectionsChanged( 1054 Conference conference, List<Connection> conferenceableConnections) { 1055 mAdapter.setConferenceableConnections( 1056 mIdByConference.get(conference), 1057 createConnectionIdList(conferenceableConnections)); 1058 } 1059 1060 @Override 1061 public void onDestroyed(Conference conference) { 1062 removeConference(conference); 1063 } 1064 1065 @Override 1066 public void onConnectionCapabilitiesChanged( 1067 Conference conference, 1068 int connectionCapabilities) { 1069 String id = mIdByConference.get(conference); 1070 Log.d(this, "call capabilities: conference: %s", 1071 Connection.capabilitiesToString(connectionCapabilities)); 1072 mAdapter.setConnectionCapabilities(id, connectionCapabilities); 1073 } 1074 1075 @Override 1076 public void onConnectionPropertiesChanged( 1077 Conference conference, 1078 int connectionProperties) { 1079 String id = mIdByConference.get(conference); 1080 Log.d(this, "call capabilities: conference: %s", 1081 Connection.propertiesToString(connectionProperties)); 1082 mAdapter.setConnectionProperties(id, connectionProperties); 1083 } 1084 1085 @Override 1086 public void onVideoStateChanged(Conference c, int videoState) { 1087 String id = mIdByConference.get(c); 1088 Log.d(this, "onVideoStateChanged set video state %d", videoState); 1089 mAdapter.setVideoState(id, videoState); 1090 } 1091 1092 @Override 1093 public void onVideoProviderChanged(Conference c, Connection.VideoProvider videoProvider) { 1094 String id = mIdByConference.get(c); 1095 Log.d(this, "onVideoProviderChanged: Connection: %s, VideoProvider: %s", c, 1096 videoProvider); 1097 mAdapter.setVideoProvider(id, videoProvider); 1098 } 1099 1100 @Override 1101 public void onStatusHintsChanged(Conference conference, StatusHints statusHints) { 1102 String id = mIdByConference.get(conference); 1103 if (id != null) { 1104 mAdapter.setStatusHints(id, statusHints); 1105 } 1106 } 1107 1108 @Override 1109 public void onExtrasChanged(Conference c, Bundle extras) { 1110 String id = mIdByConference.get(c); 1111 if (id != null) { 1112 mAdapter.putExtras(id, extras); 1113 } 1114 } 1115 1116 @Override 1117 public void onExtrasRemoved(Conference c, List<String> keys) { 1118 String id = mIdByConference.get(c); 1119 if (id != null) { 1120 mAdapter.removeExtras(id, keys); 1121 } 1122 } 1123 }; 1124 1125 private final Connection.Listener mConnectionListener = new Connection.Listener() { 1126 @Override 1127 public void onStateChanged(Connection c, int state) { 1128 String id = mIdByConnection.get(c); 1129 Log.d(this, "Adapter set state %s %s", id, Connection.stateToString(state)); 1130 switch (state) { 1131 case Connection.STATE_ACTIVE: 1132 mAdapter.setActive(id); 1133 break; 1134 case Connection.STATE_DIALING: 1135 mAdapter.setDialing(id); 1136 break; 1137 case Connection.STATE_PULLING_CALL: 1138 mAdapter.setPulling(id); 1139 break; 1140 case Connection.STATE_DISCONNECTED: 1141 // Handled in onDisconnected() 1142 break; 1143 case Connection.STATE_HOLDING: 1144 mAdapter.setOnHold(id); 1145 break; 1146 case Connection.STATE_NEW: 1147 // Nothing to tell Telecom 1148 break; 1149 case Connection.STATE_RINGING: 1150 mAdapter.setRinging(id); 1151 break; 1152 } 1153 } 1154 1155 @Override 1156 public void onDisconnected(Connection c, DisconnectCause disconnectCause) { 1157 String id = mIdByConnection.get(c); 1158 Log.d(this, "Adapter set disconnected %s", disconnectCause); 1159 mAdapter.setDisconnected(id, disconnectCause); 1160 } 1161 1162 @Override 1163 public void onVideoStateChanged(Connection c, int videoState) { 1164 String id = mIdByConnection.get(c); 1165 Log.d(this, "Adapter set video state %d", videoState); 1166 mAdapter.setVideoState(id, videoState); 1167 } 1168 1169 @Override 1170 public void onAddressChanged(Connection c, Uri address, int presentation) { 1171 String id = mIdByConnection.get(c); 1172 mAdapter.setAddress(id, address, presentation); 1173 } 1174 1175 @Override 1176 public void onCallerDisplayNameChanged( 1177 Connection c, String callerDisplayName, int presentation) { 1178 String id = mIdByConnection.get(c); 1179 mAdapter.setCallerDisplayName(id, callerDisplayName, presentation); 1180 } 1181 1182 @Override 1183 public void onDestroyed(Connection c) { 1184 removeConnection(c); 1185 } 1186 1187 @Override 1188 public void onPostDialWait(Connection c, String remaining) { 1189 String id = mIdByConnection.get(c); 1190 Log.d(this, "Adapter onPostDialWait %s, %s", c, remaining); 1191 mAdapter.onPostDialWait(id, remaining); 1192 } 1193 1194 @Override 1195 public void onPostDialChar(Connection c, char nextChar) { 1196 String id = mIdByConnection.get(c); 1197 Log.d(this, "Adapter onPostDialChar %s, %s", c, nextChar); 1198 mAdapter.onPostDialChar(id, nextChar); 1199 } 1200 1201 @Override 1202 public void onRingbackRequested(Connection c, boolean ringback) { 1203 String id = mIdByConnection.get(c); 1204 Log.d(this, "Adapter onRingback %b", ringback); 1205 mAdapter.setRingbackRequested(id, ringback); 1206 } 1207 1208 @Override 1209 public void onConnectionCapabilitiesChanged(Connection c, int capabilities) { 1210 String id = mIdByConnection.get(c); 1211 Log.d(this, "capabilities: parcelableconnection: %s", 1212 Connection.capabilitiesToString(capabilities)); 1213 mAdapter.setConnectionCapabilities(id, capabilities); 1214 } 1215 1216 @Override 1217 public void onConnectionPropertiesChanged(Connection c, int properties) { 1218 String id = mIdByConnection.get(c); 1219 Log.d(this, "properties: parcelableconnection: %s", 1220 Connection.propertiesToString(properties)); 1221 mAdapter.setConnectionProperties(id, properties); 1222 } 1223 1224 @Override 1225 public void onVideoProviderChanged(Connection c, Connection.VideoProvider videoProvider) { 1226 String id = mIdByConnection.get(c); 1227 Log.d(this, "onVideoProviderChanged: Connection: %s, VideoProvider: %s", c, 1228 videoProvider); 1229 mAdapter.setVideoProvider(id, videoProvider); 1230 } 1231 1232 @Override 1233 public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) { 1234 String id = mIdByConnection.get(c); 1235 mAdapter.setIsVoipAudioMode(id, isVoip); 1236 } 1237 1238 @Override 1239 public void onStatusHintsChanged(Connection c, StatusHints statusHints) { 1240 String id = mIdByConnection.get(c); 1241 mAdapter.setStatusHints(id, statusHints); 1242 } 1243 1244 @Override 1245 public void onConferenceablesChanged( 1246 Connection connection, List<Conferenceable> conferenceables) { 1247 mAdapter.setConferenceableConnections( 1248 mIdByConnection.get(connection), 1249 createIdList(conferenceables)); 1250 } 1251 1252 @Override 1253 public void onConferenceChanged(Connection connection, Conference conference) { 1254 String id = mIdByConnection.get(connection); 1255 if (id != null) { 1256 String conferenceId = null; 1257 if (conference != null) { 1258 conferenceId = mIdByConference.get(conference); 1259 } 1260 mAdapter.setIsConferenced(id, conferenceId); 1261 } 1262 } 1263 1264 @Override 1265 public void onConferenceMergeFailed(Connection connection) { 1266 String id = mIdByConnection.get(connection); 1267 if (id != null) { 1268 mAdapter.onConferenceMergeFailed(id); 1269 } 1270 } 1271 1272 @Override 1273 public void onExtrasChanged(Connection c, Bundle extras) { 1274 String id = mIdByConnection.get(c); 1275 if (id != null) { 1276 mAdapter.putExtras(id, extras); 1277 } 1278 } 1279 1280 @Override 1281 public void onExtrasRemoved(Connection c, List<String> keys) { 1282 String id = mIdByConnection.get(c); 1283 if (id != null) { 1284 mAdapter.removeExtras(id, keys); 1285 } 1286 } 1287 1288 @Override 1289 public void onConnectionEvent(Connection connection, String event, Bundle extras) { 1290 String id = mIdByConnection.get(connection); 1291 if (id != null) { 1292 mAdapter.onConnectionEvent(id, event, extras); 1293 } 1294 } 1295 1296 @Override 1297 public void onAudioRouteChanged(Connection c, int audioRoute) { 1298 String id = mIdByConnection.get(c); 1299 if (id != null) { 1300 mAdapter.setAudioRoute(id, audioRoute); 1301 } 1302 } 1303 1304 @Override 1305 public void onRttInitiationSuccess(Connection c) { 1306 String id = mIdByConnection.get(c); 1307 if (id != null) { 1308 mAdapter.onRttInitiationSuccess(id); 1309 } 1310 } 1311 1312 @Override 1313 public void onRttInitiationFailure(Connection c, int reason) { 1314 String id = mIdByConnection.get(c); 1315 if (id != null) { 1316 mAdapter.onRttInitiationFailure(id, reason); 1317 } 1318 } 1319 1320 @Override 1321 public void onRttSessionRemotelyTerminated(Connection c) { 1322 String id = mIdByConnection.get(c); 1323 if (id != null) { 1324 mAdapter.onRttSessionRemotelyTerminated(id); 1325 } 1326 } 1327 1328 @Override 1329 public void onRemoteRttRequest(Connection c) { 1330 String id = mIdByConnection.get(c); 1331 if (id != null) { 1332 mAdapter.onRemoteRttRequest(id); 1333 } 1334 } 1335 1336 @Override 1337 public void onPhoneAccountChanged(Connection c, PhoneAccountHandle pHandle) { 1338 String id = mIdByConnection.get(c); 1339 if (id != null) { 1340 mAdapter.onPhoneAccountChanged(id, pHandle); 1341 } 1342 } 1343 }; 1344 1345 /** {@inheritDoc} */ 1346 @Override 1347 public final IBinder onBind(Intent intent) { 1348 return mBinder; 1349 } 1350 1351 /** {@inheritDoc} */ 1352 @Override 1353 public boolean onUnbind(Intent intent) { 1354 endAllConnections(); 1355 return super.onUnbind(intent); 1356 } 1357 1358 /** 1359 * This can be used by telecom to either create a new outgoing call or attach to an existing 1360 * incoming call. In either case, telecom will cycle through a set of services and call 1361 * createConnection util a connection service cancels the process or completes it successfully. 1362 */ 1363 private void createConnection( 1364 final PhoneAccountHandle callManagerAccount, 1365 final String callId, 1366 final ConnectionRequest request, 1367 boolean isIncoming, 1368 boolean isUnknown) { 1369 Log.d(this, "createConnection, callManagerAccount: %s, callId: %s, request: %s, " + 1370 "isIncoming: %b, isUnknown: %b", callManagerAccount, callId, request, 1371 isIncoming, 1372 isUnknown); 1373 1374 Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request) 1375 : isIncoming ? onCreateIncomingConnection(callManagerAccount, request) 1376 : onCreateOutgoingConnection(callManagerAccount, request); 1377 Log.d(this, "createConnection, connection: %s", connection); 1378 if (connection == null) { 1379 connection = Connection.createFailedConnection( 1380 new DisconnectCause(DisconnectCause.ERROR)); 1381 } 1382 1383 connection.setTelecomCallId(callId); 1384 if (connection.getState() != Connection.STATE_DISCONNECTED) { 1385 addConnection(callId, connection); 1386 } 1387 1388 Uri address = connection.getAddress(); 1389 String number = address == null ? "null" : address.getSchemeSpecificPart(); 1390 Log.v(this, "createConnection, number: %s, state: %s, capabilities: %s, properties: %s", 1391 Connection.toLogSafePhoneNumber(number), 1392 Connection.stateToString(connection.getState()), 1393 Connection.capabilitiesToString(connection.getConnectionCapabilities()), 1394 Connection.propertiesToString(connection.getConnectionProperties())); 1395 1396 Log.d(this, "createConnection, calling handleCreateConnectionSuccessful %s", callId); 1397 mAdapter.handleCreateConnectionComplete( 1398 callId, 1399 request, 1400 new ParcelableConnection( 1401 request.getAccountHandle(), 1402 connection.getState(), 1403 connection.getConnectionCapabilities(), 1404 connection.getConnectionProperties(), 1405 connection.getSupportedAudioRoutes(), 1406 connection.getAddress(), 1407 connection.getAddressPresentation(), 1408 connection.getCallerDisplayName(), 1409 connection.getCallerDisplayNamePresentation(), 1410 connection.getVideoProvider() == null ? 1411 null : connection.getVideoProvider().getInterface(), 1412 connection.getVideoState(), 1413 connection.isRingbackRequested(), 1414 connection.getAudioModeIsVoip(), 1415 connection.getConnectTimeMillis(), 1416 connection.getConnectElapsedTimeMillis(), 1417 connection.getStatusHints(), 1418 connection.getDisconnectCause(), 1419 createIdList(connection.getConferenceables()), 1420 connection.getExtras())); 1421 1422 if (isIncoming && request.shouldShowIncomingCallUi() && 1423 (connection.getConnectionProperties() & Connection.PROPERTY_SELF_MANAGED) == 1424 Connection.PROPERTY_SELF_MANAGED) { 1425 // Tell ConnectionService to show its incoming call UX. 1426 connection.onShowIncomingCallUi(); 1427 } 1428 if (isUnknown) { 1429 triggerConferenceRecalculate(); 1430 } 1431 } 1432 1433 private void createConnectionFailed(final PhoneAccountHandle callManagerAccount, 1434 final String callId, final ConnectionRequest request, 1435 boolean isIncoming) { 1436 1437 Log.i(this, "createConnectionFailed %s", callId); 1438 if (isIncoming) { 1439 onCreateIncomingConnectionFailed(callManagerAccount, request); 1440 } else { 1441 onCreateOutgoingConnectionFailed(callManagerAccount, request); 1442 } 1443 } 1444 1445 /** 1446 * Called by Telecom when the creation of a new Connection has completed and it is now added 1447 * to Telecom. 1448 * @param callId The ID of the connection. 1449 */ 1450 private void notifyCreateConnectionComplete(final String callId) { 1451 Log.i(this, "notifyCreateConnectionComplete %s", callId); 1452 if (callId == null) { 1453 // This could happen if the connection fails quickly and is removed from the 1454 // ConnectionService before Telecom sends the create connection complete callback. 1455 Log.w(this, "notifyCreateConnectionComplete: callId is null."); 1456 return; 1457 } 1458 onCreateConnectionComplete(findConnectionForAction(callId, 1459 "notifyCreateConnectionComplete")); 1460 } 1461 1462 private void abort(String callId) { 1463 Log.d(this, "abort %s", callId); 1464 findConnectionForAction(callId, "abort").onAbort(); 1465 } 1466 1467 private void answerVideo(String callId, int videoState) { 1468 Log.d(this, "answerVideo %s", callId); 1469 findConnectionForAction(callId, "answer").onAnswer(videoState); 1470 } 1471 1472 private void answer(String callId) { 1473 Log.d(this, "answer %s", callId); 1474 findConnectionForAction(callId, "answer").onAnswer(); 1475 } 1476 1477 private void reject(String callId) { 1478 Log.d(this, "reject %s", callId); 1479 findConnectionForAction(callId, "reject").onReject(); 1480 } 1481 1482 private void reject(String callId, String rejectWithMessage) { 1483 Log.d(this, "reject %s with message", callId); 1484 findConnectionForAction(callId, "reject").onReject(rejectWithMessage); 1485 } 1486 1487 private void silence(String callId) { 1488 Log.d(this, "silence %s", callId); 1489 findConnectionForAction(callId, "silence").onSilence(); 1490 } 1491 1492 private void disconnect(String callId) { 1493 Log.d(this, "disconnect %s", callId); 1494 if (mConnectionById.containsKey(callId)) { 1495 findConnectionForAction(callId, "disconnect").onDisconnect(); 1496 } else { 1497 findConferenceForAction(callId, "disconnect").onDisconnect(); 1498 } 1499 } 1500 1501 private void hold(String callId) { 1502 Log.d(this, "hold %s", callId); 1503 if (mConnectionById.containsKey(callId)) { 1504 findConnectionForAction(callId, "hold").onHold(); 1505 } else { 1506 findConferenceForAction(callId, "hold").onHold(); 1507 } 1508 } 1509 1510 private void unhold(String callId) { 1511 Log.d(this, "unhold %s", callId); 1512 if (mConnectionById.containsKey(callId)) { 1513 findConnectionForAction(callId, "unhold").onUnhold(); 1514 } else { 1515 findConferenceForAction(callId, "unhold").onUnhold(); 1516 } 1517 } 1518 1519 private void onCallAudioStateChanged(String callId, CallAudioState callAudioState) { 1520 Log.d(this, "onAudioStateChanged %s %s", callId, callAudioState); 1521 if (mConnectionById.containsKey(callId)) { 1522 findConnectionForAction(callId, "onCallAudioStateChanged").setCallAudioState( 1523 callAudioState); 1524 } else { 1525 findConferenceForAction(callId, "onCallAudioStateChanged").setCallAudioState( 1526 callAudioState); 1527 } 1528 } 1529 1530 private void playDtmfTone(String callId, char digit) { 1531 Log.d(this, "playDtmfTone %s %c", callId, digit); 1532 if (mConnectionById.containsKey(callId)) { 1533 findConnectionForAction(callId, "playDtmfTone").onPlayDtmfTone(digit); 1534 } else { 1535 findConferenceForAction(callId, "playDtmfTone").onPlayDtmfTone(digit); 1536 } 1537 } 1538 1539 private void stopDtmfTone(String callId) { 1540 Log.d(this, "stopDtmfTone %s", callId); 1541 if (mConnectionById.containsKey(callId)) { 1542 findConnectionForAction(callId, "stopDtmfTone").onStopDtmfTone(); 1543 } else { 1544 findConferenceForAction(callId, "stopDtmfTone").onStopDtmfTone(); 1545 } 1546 } 1547 1548 private void conference(String callId1, String callId2) { 1549 Log.d(this, "conference %s, %s", callId1, callId2); 1550 1551 // Attempt to get second connection or conference. 1552 Connection connection2 = findConnectionForAction(callId2, "conference"); 1553 Conference conference2 = getNullConference(); 1554 if (connection2 == getNullConnection()) { 1555 conference2 = findConferenceForAction(callId2, "conference"); 1556 if (conference2 == getNullConference()) { 1557 Log.w(this, "Connection2 or Conference2 missing in conference request %s.", 1558 callId2); 1559 return; 1560 } 1561 } 1562 1563 // Attempt to get first connection or conference and perform merge. 1564 Connection connection1 = findConnectionForAction(callId1, "conference"); 1565 if (connection1 == getNullConnection()) { 1566 Conference conference1 = findConferenceForAction(callId1, "addConnection"); 1567 if (conference1 == getNullConference()) { 1568 Log.w(this, 1569 "Connection1 or Conference1 missing in conference request %s.", 1570 callId1); 1571 } else { 1572 // Call 1 is a conference. 1573 if (connection2 != getNullConnection()) { 1574 // Call 2 is a connection so merge via call 1 (conference). 1575 conference1.onMerge(connection2); 1576 } else { 1577 // Call 2 is ALSO a conference; this should never happen. 1578 Log.wtf(this, "There can only be one conference and an attempt was made to " + 1579 "merge two conferences."); 1580 return; 1581 } 1582 } 1583 } else { 1584 // Call 1 is a connection. 1585 if (conference2 != getNullConference()) { 1586 // Call 2 is a conference, so merge via call 2. 1587 conference2.onMerge(connection1); 1588 } else { 1589 // Call 2 is a connection, so merge together. 1590 onConference(connection1, connection2); 1591 } 1592 } 1593 } 1594 1595 private void splitFromConference(String callId) { 1596 Log.d(this, "splitFromConference(%s)", callId); 1597 1598 Connection connection = findConnectionForAction(callId, "splitFromConference"); 1599 if (connection == getNullConnection()) { 1600 Log.w(this, "Connection missing in conference request %s.", callId); 1601 return; 1602 } 1603 1604 Conference conference = connection.getConference(); 1605 if (conference != null) { 1606 conference.onSeparate(connection); 1607 } 1608 } 1609 1610 private void mergeConference(String callId) { 1611 Log.d(this, "mergeConference(%s)", callId); 1612 Conference conference = findConferenceForAction(callId, "mergeConference"); 1613 if (conference != null) { 1614 conference.onMerge(); 1615 } 1616 } 1617 1618 private void swapConference(String callId) { 1619 Log.d(this, "swapConference(%s)", callId); 1620 Conference conference = findConferenceForAction(callId, "swapConference"); 1621 if (conference != null) { 1622 conference.onSwap(); 1623 } 1624 } 1625 1626 /** 1627 * Notifies a {@link Connection} of a request to pull an external call. 1628 * 1629 * See {@link Call#pullExternalCall()}. 1630 * 1631 * @param callId The ID of the call to pull. 1632 */ 1633 private void pullExternalCall(String callId) { 1634 Log.d(this, "pullExternalCall(%s)", callId); 1635 Connection connection = findConnectionForAction(callId, "pullExternalCall"); 1636 if (connection != null) { 1637 connection.onPullExternalCall(); 1638 } 1639 } 1640 1641 /** 1642 * Notifies a {@link Connection} of a call event. 1643 * 1644 * See {@link Call#sendCallEvent(String, Bundle)}. 1645 * 1646 * @param callId The ID of the call receiving the event. 1647 * @param event The event. 1648 * @param extras Extras associated with the event. 1649 */ 1650 private void sendCallEvent(String callId, String event, Bundle extras) { 1651 Log.d(this, "sendCallEvent(%s, %s)", callId, event); 1652 Connection connection = findConnectionForAction(callId, "sendCallEvent"); 1653 if (connection != null) { 1654 connection.onCallEvent(event, extras); 1655 } 1656 } 1657 1658 /** 1659 * Notifies a {@link Connection} or {@link Conference} of a change to the extras from Telecom. 1660 * <p> 1661 * These extra changes can originate from Telecom itself, or from an {@link InCallService} via 1662 * the {@link android.telecom.Call#putExtra(String, boolean)}, 1663 * {@link android.telecom.Call#putExtra(String, int)}, 1664 * {@link android.telecom.Call#putExtra(String, String)}, 1665 * {@link Call#removeExtras(List)}. 1666 * 1667 * @param callId The ID of the call receiving the event. 1668 * @param extras The new extras bundle. 1669 */ 1670 private void handleExtrasChanged(String callId, Bundle extras) { 1671 Log.d(this, "handleExtrasChanged(%s, %s)", callId, extras); 1672 if (mConnectionById.containsKey(callId)) { 1673 findConnectionForAction(callId, "handleExtrasChanged").handleExtrasChanged(extras); 1674 } else if (mConferenceById.containsKey(callId)) { 1675 findConferenceForAction(callId, "handleExtrasChanged").handleExtrasChanged(extras); 1676 } 1677 } 1678 1679 private void startRtt(String callId, Connection.RttTextStream rttTextStream) { 1680 Log.d(this, "startRtt(%s)", callId); 1681 if (mConnectionById.containsKey(callId)) { 1682 findConnectionForAction(callId, "startRtt").onStartRtt(rttTextStream); 1683 } else if (mConferenceById.containsKey(callId)) { 1684 Log.w(this, "startRtt called on a conference."); 1685 } 1686 } 1687 1688 private void stopRtt(String callId) { 1689 Log.d(this, "stopRtt(%s)", callId); 1690 if (mConnectionById.containsKey(callId)) { 1691 findConnectionForAction(callId, "stopRtt").onStopRtt(); 1692 findConnectionForAction(callId, "stopRtt").unsetRttProperty(); 1693 } else if (mConferenceById.containsKey(callId)) { 1694 Log.w(this, "stopRtt called on a conference."); 1695 } 1696 } 1697 1698 private void handleRttUpgradeResponse(String callId, Connection.RttTextStream rttTextStream) { 1699 Log.d(this, "handleRttUpgradeResponse(%s, %s)", callId, rttTextStream == null); 1700 if (mConnectionById.containsKey(callId)) { 1701 findConnectionForAction(callId, "handleRttUpgradeResponse") 1702 .handleRttUpgradeResponse(rttTextStream); 1703 } else if (mConferenceById.containsKey(callId)) { 1704 Log.w(this, "handleRttUpgradeResponse called on a conference."); 1705 } 1706 } 1707 1708 private void onPostDialContinue(String callId, boolean proceed) { 1709 Log.d(this, "onPostDialContinue(%s)", callId); 1710 findConnectionForAction(callId, "stopDtmfTone").onPostDialContinue(proceed); 1711 } 1712 1713 private void onAdapterAttached() { 1714 if (mAreAccountsInitialized) { 1715 // No need to query again if we already did it. 1716 return; 1717 } 1718 1719 mAdapter.queryRemoteConnectionServices(new RemoteServiceCallback.Stub() { 1720 @Override 1721 public void onResult( 1722 final List<ComponentName> componentNames, 1723 final List<IBinder> services) { 1724 mHandler.post(new android.telecom.Logging.Runnable("oAA.qRCS.oR", null /*lock*/) { 1725 @Override 1726 public void loggedRun() { 1727 for (int i = 0; i < componentNames.size() && i < services.size(); i++) { 1728 mRemoteConnectionManager.addConnectionService( 1729 componentNames.get(i), 1730 IConnectionService.Stub.asInterface(services.get(i))); 1731 } 1732 onAccountsInitialized(); 1733 Log.d(this, "remote connection services found: " + services); 1734 } 1735 }.prepare()); 1736 } 1737 1738 @Override 1739 public void onError() { 1740 mHandler.post(new android.telecom.Logging.Runnable("oAA.qRCS.oE", null /*lock*/) { 1741 @Override 1742 public void loggedRun() { 1743 mAreAccountsInitialized = true; 1744 } 1745 }.prepare()); 1746 } 1747 }); 1748 } 1749 1750 /** 1751 * Ask some other {@code ConnectionService} to create a {@code RemoteConnection} given an 1752 * incoming request. This is used by {@code ConnectionService}s that are registered with 1753 * {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER} and want to be able to manage 1754 * SIM-based incoming calls. 1755 * 1756 * @param connectionManagerPhoneAccount See description at 1757 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}. 1758 * @param request Details about the incoming call. 1759 * @return The {@code Connection} object to satisfy this call, or {@code null} to 1760 * not handle the call. 1761 */ 1762 public final RemoteConnection createRemoteIncomingConnection( 1763 PhoneAccountHandle connectionManagerPhoneAccount, 1764 ConnectionRequest request) { 1765 return mRemoteConnectionManager.createRemoteConnection( 1766 connectionManagerPhoneAccount, request, true); 1767 } 1768 1769 /** 1770 * Ask some other {@code ConnectionService} to create a {@code RemoteConnection} given an 1771 * outgoing request. This is used by {@code ConnectionService}s that are registered with 1772 * {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER} and want to be able to use the 1773 * SIM-based {@code ConnectionService} to place its outgoing calls. 1774 * 1775 * @param connectionManagerPhoneAccount See description at 1776 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}. 1777 * @param request Details about the outgoing call. 1778 * @return The {@code Connection} object to satisfy this call, or {@code null} to 1779 * not handle the call. 1780 */ 1781 public final RemoteConnection createRemoteOutgoingConnection( 1782 PhoneAccountHandle connectionManagerPhoneAccount, 1783 ConnectionRequest request) { 1784 return mRemoteConnectionManager.createRemoteConnection( 1785 connectionManagerPhoneAccount, request, false); 1786 } 1787 1788 /** 1789 * Indicates to the relevant {@code RemoteConnectionService} that the specified 1790 * {@link RemoteConnection}s should be merged into a conference call. 1791 * <p> 1792 * If the conference request is successful, the method {@link #onRemoteConferenceAdded} will 1793 * be invoked. 1794 * 1795 * @param remoteConnection1 The first of the remote connections to conference. 1796 * @param remoteConnection2 The second of the remote connections to conference. 1797 */ 1798 public final void conferenceRemoteConnections( 1799 RemoteConnection remoteConnection1, 1800 RemoteConnection remoteConnection2) { 1801 mRemoteConnectionManager.conferenceRemoteConnections(remoteConnection1, remoteConnection2); 1802 } 1803 1804 /** 1805 * Adds a new conference call. When a conference call is created either as a result of an 1806 * explicit request via {@link #onConference} or otherwise, the connection service should supply 1807 * an instance of {@link Conference} by invoking this method. A conference call provided by this 1808 * method will persist until {@link Conference#destroy} is invoked on the conference instance. 1809 * 1810 * @param conference The new conference object. 1811 */ 1812 public final void addConference(Conference conference) { 1813 Log.d(this, "addConference: conference=%s", conference); 1814 1815 String id = addConferenceInternal(conference); 1816 if (id != null) { 1817 List<String> connectionIds = new ArrayList<>(2); 1818 for (Connection connection : conference.getConnections()) { 1819 if (mIdByConnection.containsKey(connection)) { 1820 connectionIds.add(mIdByConnection.get(connection)); 1821 } 1822 } 1823 conference.setTelecomCallId(id); 1824 ParcelableConference parcelableConference = new ParcelableConference( 1825 conference.getPhoneAccountHandle(), 1826 conference.getState(), 1827 conference.getConnectionCapabilities(), 1828 conference.getConnectionProperties(), 1829 connectionIds, 1830 conference.getVideoProvider() == null ? 1831 null : conference.getVideoProvider().getInterface(), 1832 conference.getVideoState(), 1833 conference.getConnectTimeMillis(), 1834 conference.getConnectElapsedTime(), 1835 conference.getStatusHints(), 1836 conference.getExtras()); 1837 1838 mAdapter.addConferenceCall(id, parcelableConference); 1839 mAdapter.setVideoProvider(id, conference.getVideoProvider()); 1840 mAdapter.setVideoState(id, conference.getVideoState()); 1841 1842 // Go through any child calls and set the parent. 1843 for (Connection connection : conference.getConnections()) { 1844 String connectionId = mIdByConnection.get(connection); 1845 if (connectionId != null) { 1846 mAdapter.setIsConferenced(connectionId, id); 1847 } 1848 } 1849 } 1850 } 1851 1852 /** 1853 * Adds a connection created by the {@link ConnectionService} and informs telecom of the new 1854 * connection. 1855 * 1856 * @param phoneAccountHandle The phone account handle for the connection. 1857 * @param connection The connection to add. 1858 */ 1859 public final void addExistingConnection(PhoneAccountHandle phoneAccountHandle, 1860 Connection connection) { 1861 addExistingConnection(phoneAccountHandle, connection, null /* conference */); 1862 } 1863 1864 /** 1865 * Adds a connection created by the {@link ConnectionService} and informs telecom of the new 1866 * connection. 1867 * 1868 * @param phoneAccountHandle The phone account handle for the connection. 1869 * @param connection The connection to add. 1870 * @param conference The parent conference of the new connection. 1871 * @hide 1872 */ 1873 public final void addExistingConnection(PhoneAccountHandle phoneAccountHandle, 1874 Connection connection, Conference conference) { 1875 1876 String id = addExistingConnectionInternal(phoneAccountHandle, connection); 1877 if (id != null) { 1878 List<String> emptyList = new ArrayList<>(0); 1879 String conferenceId = null; 1880 if (conference != null) { 1881 conferenceId = mIdByConference.get(conference); 1882 } 1883 1884 ParcelableConnection parcelableConnection = new ParcelableConnection( 1885 phoneAccountHandle, 1886 connection.getState(), 1887 connection.getConnectionCapabilities(), 1888 connection.getConnectionProperties(), 1889 connection.getSupportedAudioRoutes(), 1890 connection.getAddress(), 1891 connection.getAddressPresentation(), 1892 connection.getCallerDisplayName(), 1893 connection.getCallerDisplayNamePresentation(), 1894 connection.getVideoProvider() == null ? 1895 null : connection.getVideoProvider().getInterface(), 1896 connection.getVideoState(), 1897 connection.isRingbackRequested(), 1898 connection.getAudioModeIsVoip(), 1899 connection.getConnectTimeMillis(), 1900 connection.getConnectElapsedTimeMillis(), 1901 connection.getStatusHints(), 1902 connection.getDisconnectCause(), 1903 emptyList, 1904 connection.getExtras(), 1905 conferenceId); 1906 mAdapter.addExistingConnection(id, parcelableConnection); 1907 } 1908 } 1909 1910 /** 1911 * Returns all the active {@code Connection}s for which this {@code ConnectionService} 1912 * has taken responsibility. 1913 * 1914 * @return A collection of {@code Connection}s created by this {@code ConnectionService}. 1915 */ 1916 public final Collection<Connection> getAllConnections() { 1917 return mConnectionById.values(); 1918 } 1919 1920 /** 1921 * Returns all the active {@code Conference}s for which this {@code ConnectionService} 1922 * has taken responsibility. 1923 * 1924 * @return A collection of {@code Conference}s created by this {@code ConnectionService}. 1925 */ 1926 public final Collection<Conference> getAllConferences() { 1927 return mConferenceById.values(); 1928 } 1929 1930 /** 1931 * Create a {@code Connection} given an incoming request. This is used to attach to existing 1932 * incoming calls. 1933 * 1934 * @param connectionManagerPhoneAccount See description at 1935 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}. 1936 * @param request Details about the incoming call. 1937 * @return The {@code Connection} object to satisfy this call, or {@code null} to 1938 * not handle the call. 1939 */ 1940 public Connection onCreateIncomingConnection( 1941 PhoneAccountHandle connectionManagerPhoneAccount, 1942 ConnectionRequest request) { 1943 return null; 1944 } 1945 1946 /** 1947 * Called after the {@link Connection} returned by 1948 * {@link #onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)} 1949 * or {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)} has been 1950 * added to the {@link ConnectionService} and sent to Telecom. 1951 * 1952 * @param connection the {@link Connection}. 1953 * @hide 1954 */ 1955 public void onCreateConnectionComplete(Connection connection) { 1956 } 1957 1958 /** 1959 * Called by Telecom to inform the {@link ConnectionService} that its request to create a new 1960 * incoming {@link Connection} was denied. 1961 * <p> 1962 * Used when a self-managed {@link ConnectionService} attempts to create a new incoming 1963 * {@link Connection}, but Telecom has determined that the call cannot be allowed at this time. 1964 * The {@link ConnectionService} is responsible for silently rejecting the new incoming 1965 * {@link Connection}. 1966 * <p> 1967 * See {@link TelecomManager#isIncomingCallPermitted(PhoneAccountHandle)} for more information. 1968 * 1969 * @param connectionManagerPhoneAccount See description at 1970 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}. 1971 * @param request The incoming connection request. 1972 */ 1973 public void onCreateIncomingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount, 1974 ConnectionRequest request) { 1975 } 1976 1977 /** 1978 * Called by Telecom to inform the {@link ConnectionService} that its request to create a new 1979 * outgoing {@link Connection} was denied. 1980 * <p> 1981 * Used when a self-managed {@link ConnectionService} attempts to create a new outgoing 1982 * {@link Connection}, but Telecom has determined that the call cannot be placed at this time. 1983 * The {@link ConnectionService} is responisible for informing the user that the 1984 * {@link Connection} cannot be made at this time. 1985 * <p> 1986 * See {@link TelecomManager#isOutgoingCallPermitted(PhoneAccountHandle)} for more information. 1987 * 1988 * @param connectionManagerPhoneAccount See description at 1989 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}. 1990 * @param request The outgoing connection request. 1991 */ 1992 public void onCreateOutgoingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount, 1993 ConnectionRequest request) { 1994 } 1995 1996 /** 1997 * Trigger recalculate functinality for conference calls. This is used when a Telephony 1998 * Connection is part of a conference controller but is not yet added to Connection 1999 * Service and hence cannot be added to the conference call. 2000 * 2001 * @hide 2002 */ 2003 public void triggerConferenceRecalculate() { 2004 } 2005 2006 /** 2007 * Create a {@code Connection} given an outgoing request. This is used to initiate new 2008 * outgoing calls. 2009 * 2010 * @param connectionManagerPhoneAccount The connection manager account to use for managing 2011 * this call. 2012 * <p> 2013 * If this parameter is not {@code null}, it means that this {@code ConnectionService} 2014 * has registered one or more {@code PhoneAccount}s having 2015 * {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}. This parameter will contain 2016 * one of these {@code PhoneAccount}s, while the {@code request} will contain another 2017 * (usually but not always distinct) {@code PhoneAccount} to be used for actually 2018 * making the connection. 2019 * <p> 2020 * If this parameter is {@code null}, it means that this {@code ConnectionService} is 2021 * being asked to make a direct connection. The 2022 * {@link ConnectionRequest#getAccountHandle()} of parameter {@code request} will be 2023 * a {@code PhoneAccount} registered by this {@code ConnectionService} to use for 2024 * making the connection. 2025 * @param request Details about the outgoing call. 2026 * @return The {@code Connection} object to satisfy this call, or the result of an invocation 2027 * of {@link Connection#createFailedConnection(DisconnectCause)} to not handle the call. 2028 */ 2029 public Connection onCreateOutgoingConnection( 2030 PhoneAccountHandle connectionManagerPhoneAccount, 2031 ConnectionRequest request) { 2032 return null; 2033 } 2034 2035 /** 2036 * Create a {@code Connection} for a new unknown call. An unknown call is a call originating 2037 * from the ConnectionService that was neither a user-initiated outgoing call, nor an incoming 2038 * call created using 2039 * {@code TelecomManager#addNewIncomingCall(PhoneAccountHandle, android.os.Bundle)}. 2040 * 2041 * @hide 2042 */ 2043 public Connection onCreateUnknownConnection(PhoneAccountHandle connectionManagerPhoneAccount, 2044 ConnectionRequest request) { 2045 return null; 2046 } 2047 2048 /** 2049 * Conference two specified connections. Invoked when the user has made a request to merge the 2050 * specified connections into a conference call. In response, the connection service should 2051 * create an instance of {@link Conference} and pass it into {@link #addConference}. 2052 * 2053 * @param connection1 A connection to merge into a conference call. 2054 * @param connection2 A connection to merge into a conference call. 2055 */ 2056 public void onConference(Connection connection1, Connection connection2) {} 2057 2058 /** 2059 * Indicates that a remote conference has been created for existing {@link RemoteConnection}s. 2060 * When this method is invoked, this {@link ConnectionService} should create its own 2061 * representation of the conference call and send it to telecom using {@link #addConference}. 2062 * <p> 2063 * This is only relevant to {@link ConnectionService}s which are registered with 2064 * {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}. 2065 * 2066 * @param conference The remote conference call. 2067 */ 2068 public void onRemoteConferenceAdded(RemoteConference conference) {} 2069 2070 /** 2071 * Called when an existing connection is added remotely. 2072 * @param connection The existing connection which was added. 2073 */ 2074 public void onRemoteExistingConnectionAdded(RemoteConnection connection) {} 2075 2076 /** 2077 * @hide 2078 */ 2079 public boolean containsConference(Conference conference) { 2080 return mIdByConference.containsKey(conference); 2081 } 2082 2083 /** {@hide} */ 2084 void addRemoteConference(RemoteConference remoteConference) { 2085 onRemoteConferenceAdded(remoteConference); 2086 } 2087 2088 /** {@hide} */ 2089 void addRemoteExistingConnection(RemoteConnection remoteConnection) { 2090 onRemoteExistingConnectionAdded(remoteConnection); 2091 } 2092 2093 private void onAccountsInitialized() { 2094 mAreAccountsInitialized = true; 2095 for (Runnable r : mPreInitializationConnectionRequests) { 2096 r.run(); 2097 } 2098 mPreInitializationConnectionRequests.clear(); 2099 } 2100 2101 /** 2102 * Adds an existing connection to the list of connections, identified by a new call ID unique 2103 * to this connection service. 2104 * 2105 * @param connection The connection. 2106 * @return The ID of the connection (e.g. the call-id). 2107 */ 2108 private String addExistingConnectionInternal(PhoneAccountHandle handle, Connection connection) { 2109 String id; 2110 2111 if (connection.getExtras() != null && connection.getExtras() 2112 .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) { 2113 id = connection.getExtras().getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID); 2114 Log.d(this, "addExistingConnectionInternal - conn %s reusing original id %s", 2115 connection.getTelecomCallId(), id); 2116 } else if (handle == null) { 2117 // If no phone account handle was provided, we cannot be sure the call ID is unique, 2118 // so just use a random UUID. 2119 id = UUID.randomUUID().toString(); 2120 } else { 2121 // Phone account handle was provided, so use the ConnectionService class name as a 2122 // prefix for a unique incremental call ID. 2123 id = handle.getComponentName().getClassName() + "@" + getNextCallId(); 2124 } 2125 addConnection(id, connection); 2126 return id; 2127 } 2128 2129 private void addConnection(String callId, Connection connection) { 2130 connection.setTelecomCallId(callId); 2131 mConnectionById.put(callId, connection); 2132 mIdByConnection.put(connection, callId); 2133 connection.addConnectionListener(mConnectionListener); 2134 connection.setConnectionService(this); 2135 } 2136 2137 /** {@hide} */ 2138 protected void removeConnection(Connection connection) { 2139 connection.unsetConnectionService(this); 2140 connection.removeConnectionListener(mConnectionListener); 2141 String id = mIdByConnection.get(connection); 2142 if (id != null) { 2143 mConnectionById.remove(id); 2144 mIdByConnection.remove(connection); 2145 mAdapter.removeCall(id); 2146 } 2147 } 2148 2149 private String addConferenceInternal(Conference conference) { 2150 String originalId = null; 2151 if (conference.getExtras() != null && conference.getExtras() 2152 .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) { 2153 originalId = conference.getExtras().getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID); 2154 Log.d(this, "addConferenceInternal: conf %s reusing original id %s", 2155 conference.getTelecomCallId(), 2156 originalId); 2157 } 2158 if (mIdByConference.containsKey(conference)) { 2159 Log.w(this, "Re-adding an existing conference: %s.", conference); 2160 } else if (conference != null) { 2161 // Conferences do not (yet) have a PhoneAccountHandle associated with them, so we 2162 // cannot determine a ConnectionService class name to associate with the ID, so use 2163 // a unique UUID (for now). 2164 String id = originalId == null ? UUID.randomUUID().toString() : originalId; 2165 mConferenceById.put(id, conference); 2166 mIdByConference.put(conference, id); 2167 conference.addListener(mConferenceListener); 2168 return id; 2169 } 2170 2171 return null; 2172 } 2173 2174 private void removeConference(Conference conference) { 2175 if (mIdByConference.containsKey(conference)) { 2176 conference.removeListener(mConferenceListener); 2177 2178 String id = mIdByConference.get(conference); 2179 mConferenceById.remove(id); 2180 mIdByConference.remove(conference); 2181 mAdapter.removeCall(id); 2182 } 2183 } 2184 2185 private Connection findConnectionForAction(String callId, String action) { 2186 if (callId != null && mConnectionById.containsKey(callId)) { 2187 return mConnectionById.get(callId); 2188 } 2189 Log.w(this, "%s - Cannot find Connection %s", action, callId); 2190 return getNullConnection(); 2191 } 2192 2193 static synchronized Connection getNullConnection() { 2194 if (sNullConnection == null) { 2195 sNullConnection = new Connection() {}; 2196 } 2197 return sNullConnection; 2198 } 2199 2200 private Conference findConferenceForAction(String conferenceId, String action) { 2201 if (mConferenceById.containsKey(conferenceId)) { 2202 return mConferenceById.get(conferenceId); 2203 } 2204 Log.w(this, "%s - Cannot find conference %s", action, conferenceId); 2205 return getNullConference(); 2206 } 2207 2208 private List<String> createConnectionIdList(List<Connection> connections) { 2209 List<String> ids = new ArrayList<>(); 2210 for (Connection c : connections) { 2211 if (mIdByConnection.containsKey(c)) { 2212 ids.add(mIdByConnection.get(c)); 2213 } 2214 } 2215 Collections.sort(ids); 2216 return ids; 2217 } 2218 2219 /** 2220 * Builds a list of {@link Connection} and {@link Conference} IDs based on the list of 2221 * {@link Conferenceable}s passed in. 2222 * 2223 * @param conferenceables The {@link Conferenceable} connections and conferences. 2224 * @return List of string conference and call Ids. 2225 */ 2226 private List<String> createIdList(List<Conferenceable> conferenceables) { 2227 List<String> ids = new ArrayList<>(); 2228 for (Conferenceable c : conferenceables) { 2229 // Only allow Connection and Conference conferenceables. 2230 if (c instanceof Connection) { 2231 Connection connection = (Connection) c; 2232 if (mIdByConnection.containsKey(connection)) { 2233 ids.add(mIdByConnection.get(connection)); 2234 } 2235 } else if (c instanceof Conference) { 2236 Conference conference = (Conference) c; 2237 if (mIdByConference.containsKey(conference)) { 2238 ids.add(mIdByConference.get(conference)); 2239 } 2240 } 2241 } 2242 Collections.sort(ids); 2243 return ids; 2244 } 2245 2246 private Conference getNullConference() { 2247 if (sNullConference == null) { 2248 sNullConference = new Conference(null) {}; 2249 } 2250 return sNullConference; 2251 } 2252 2253 private void endAllConnections() { 2254 // Unbound from telecomm. We should end all connections and conferences. 2255 for (Connection connection : mIdByConnection.keySet()) { 2256 // only operate on top-level calls. Conference calls will be removed on their own. 2257 if (connection.getConference() == null) { 2258 connection.onDisconnect(); 2259 } 2260 } 2261 for (Conference conference : mIdByConference.keySet()) { 2262 conference.onDisconnect(); 2263 } 2264 } 2265 2266 /** 2267 * Retrieves the next call ID as maintainted by the connection service. 2268 * 2269 * @return The call ID. 2270 */ 2271 private int getNextCallId() { 2272 synchronized (mIdSyncRoot) { 2273 return ++mId; 2274 } 2275 } 2276} 2277