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 17 package android.telecom; 18 19 import android.annotation.CallbackExecutor; 20 import android.annotation.NonNull; 21 import android.location.Location; 22 import android.net.Uri; 23 import android.os.Binder; 24 import android.os.Bundle; 25 import android.os.IBinder.DeathRecipient; 26 import android.os.OutcomeReceiver; 27 import android.os.RemoteException; 28 import android.os.ResultReceiver; 29 30 import com.android.internal.telecom.IConnectionServiceAdapter; 31 import com.android.internal.telecom.RemoteServiceCallback; 32 33 import java.util.Collections; 34 import java.util.Iterator; 35 import java.util.List; 36 import java.util.Set; 37 import java.util.concurrent.ConcurrentHashMap; 38 import java.util.concurrent.Executor; 39 40 /** 41 * Provides methods for IConnectionService implementations to interact with the system phone app. 42 * 43 * @hide 44 */ 45 final class ConnectionServiceAdapter implements DeathRecipient { 46 /** 47 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is 48 * load factor before resizing, 1 means we only expect a single thread to 49 * access the map so make only a single shard 50 */ 51 private final Set<IConnectionServiceAdapter> mAdapters = Collections.newSetFromMap( 52 new ConcurrentHashMap<IConnectionServiceAdapter, Boolean>(8, 0.9f, 1)); 53 ConnectionServiceAdapter()54 ConnectionServiceAdapter() { 55 } 56 addAdapter(IConnectionServiceAdapter adapter)57 void addAdapter(IConnectionServiceAdapter adapter) { 58 for (IConnectionServiceAdapter it : mAdapters) { 59 if (it.asBinder() == adapter.asBinder()) { 60 Log.w(this, "Ignoring duplicate adapter addition."); 61 return; 62 } 63 } 64 if (mAdapters.add(adapter)) { 65 try { 66 adapter.asBinder().linkToDeath(this, 0); 67 } catch (RemoteException e) { 68 mAdapters.remove(adapter); 69 } 70 } 71 } 72 removeAdapter(IConnectionServiceAdapter adapter)73 void removeAdapter(IConnectionServiceAdapter adapter) { 74 if (adapter != null) { 75 for (IConnectionServiceAdapter it : mAdapters) { 76 if (it.asBinder() == adapter.asBinder() && mAdapters.remove(it)) { 77 adapter.asBinder().unlinkToDeath(this, 0); 78 break; 79 } 80 } 81 } 82 } 83 84 /** ${inheritDoc} */ 85 @Override binderDied()86 public void binderDied() { 87 Iterator<IConnectionServiceAdapter> it = mAdapters.iterator(); 88 while (it.hasNext()) { 89 IConnectionServiceAdapter adapter = it.next(); 90 if (!adapter.asBinder().isBinderAlive()) { 91 it.remove(); 92 adapter.asBinder().unlinkToDeath(this, 0); 93 } 94 } 95 } 96 handleCreateConnectionComplete( String id, ConnectionRequest request, ParcelableConnection connection)97 void handleCreateConnectionComplete( 98 String id, 99 ConnectionRequest request, 100 ParcelableConnection connection) { 101 for (IConnectionServiceAdapter adapter : mAdapters) { 102 try { 103 adapter.handleCreateConnectionComplete(id, request, connection, 104 Log.getExternalSession()); 105 } catch (RemoteException e) { 106 } 107 } 108 } 109 handleCreateConferenceComplete( String id, ConnectionRequest request, ParcelableConference conference)110 void handleCreateConferenceComplete( 111 String id, 112 ConnectionRequest request, 113 ParcelableConference conference) { 114 for (IConnectionServiceAdapter adapter : mAdapters) { 115 try { 116 adapter.handleCreateConferenceComplete(id, request, conference, 117 Log.getExternalSession()); 118 } catch (RemoteException e) { 119 } 120 } 121 } 122 123 /** 124 * Sets a call's state to active (e.g., an ongoing call where two parties can actively 125 * communicate). 126 * 127 * @param callId The unique ID of the call whose state is changing to active. 128 */ setActive(String callId)129 void setActive(String callId) { 130 for (IConnectionServiceAdapter adapter : mAdapters) { 131 try { 132 adapter.setActive(callId, Log.getExternalSession()); 133 } catch (RemoteException e) { 134 } 135 } 136 } 137 138 /** 139 * Sets a call's state to ringing (e.g., an inbound ringing call). 140 * 141 * @param callId The unique ID of the call whose state is changing to ringing. 142 */ setRinging(String callId)143 void setRinging(String callId) { 144 for (IConnectionServiceAdapter adapter : mAdapters) { 145 try { 146 adapter.setRinging(callId, Log.getExternalSession()); 147 } catch (RemoteException e) { 148 } 149 } 150 } 151 152 /** 153 * Sets a call's state to dialing (e.g., dialing an outbound call). 154 * 155 * @param callId The unique ID of the call whose state is changing to dialing. 156 */ setDialing(String callId)157 void setDialing(String callId) { 158 for (IConnectionServiceAdapter adapter : mAdapters) { 159 try { 160 adapter.setDialing(callId, Log.getExternalSession()); 161 } catch (RemoteException e) { 162 } 163 } 164 } 165 166 /** 167 * Sets a call's state to pulling (e.g. a call with {@link Connection#PROPERTY_IS_EXTERNAL_CALL} 168 * is being pulled to the local device. 169 * 170 * @param callId The unique ID of the call whose state is changing to dialing. 171 */ setPulling(String callId)172 void setPulling(String callId) { 173 for (IConnectionServiceAdapter adapter : mAdapters) { 174 try { 175 adapter.setPulling(callId, Log.getExternalSession()); 176 } catch (RemoteException e) { 177 } 178 } 179 } 180 181 /** 182 * Sets a call's state to disconnected. 183 * 184 * @param callId The unique ID of the call whose state is changing to disconnected. 185 * @param disconnectCause The reason for the disconnection, as described by 186 * {@link android.telecomm.DisconnectCause}. 187 */ setDisconnected(String callId, DisconnectCause disconnectCause)188 void setDisconnected(String callId, DisconnectCause disconnectCause) { 189 for (IConnectionServiceAdapter adapter : mAdapters) { 190 try { 191 adapter.setDisconnected(callId, disconnectCause, Log.getExternalSession()); 192 } catch (RemoteException e) { 193 } 194 } 195 } 196 197 /** 198 * Sets a call's state to be on hold. 199 * 200 * @param callId - The unique ID of the call whose state is changing to be on hold. 201 */ setOnHold(String callId)202 void setOnHold(String callId) { 203 for (IConnectionServiceAdapter adapter : mAdapters) { 204 try { 205 adapter.setOnHold(callId, Log.getExternalSession()); 206 } catch (RemoteException e) { 207 } 208 } 209 } 210 211 /** 212 * Asks Telecom to start or stop a ringback tone for a call. 213 * 214 * @param callId The unique ID of the call whose ringback is being changed. 215 * @param ringback Whether Telecom should start playing a ringback tone. 216 */ setRingbackRequested(String callId, boolean ringback)217 void setRingbackRequested(String callId, boolean ringback) { 218 for (IConnectionServiceAdapter adapter : mAdapters) { 219 try { 220 adapter.setRingbackRequested(callId, ringback, Log.getExternalSession()); 221 } catch (RemoteException e) { 222 } 223 } 224 } 225 setConnectionCapabilities(String callId, int capabilities)226 void setConnectionCapabilities(String callId, int capabilities) { 227 for (IConnectionServiceAdapter adapter : mAdapters) { 228 try { 229 adapter.setConnectionCapabilities(callId, capabilities, Log.getExternalSession()); 230 } catch (RemoteException ignored) { 231 } 232 } 233 } 234 setConnectionProperties(String callId, int properties)235 void setConnectionProperties(String callId, int properties) { 236 for (IConnectionServiceAdapter adapter : mAdapters) { 237 try { 238 adapter.setConnectionProperties(callId, properties, Log.getExternalSession()); 239 } catch (RemoteException ignored) { 240 } 241 } 242 } 243 244 /** 245 * Indicates whether or not the specified call is currently conferenced into the specified 246 * conference call. 247 * 248 * @param callId The unique ID of the call being conferenced. 249 * @param conferenceCallId The unique ID of the conference call. Null if call is not 250 * conferenced. 251 */ setIsConferenced(String callId, String conferenceCallId)252 void setIsConferenced(String callId, String conferenceCallId) { 253 for (IConnectionServiceAdapter adapter : mAdapters) { 254 try { 255 Log.d(this, "sending connection %s with conference %s", callId, conferenceCallId); 256 adapter.setIsConferenced(callId, conferenceCallId, Log.getExternalSession()); 257 } catch (RemoteException ignored) { 258 } 259 } 260 } 261 262 /** 263 * Indicates that the merge request on this call has failed. 264 * 265 * @param callId The unique ID of the call being conferenced. 266 */ onConferenceMergeFailed(String callId)267 void onConferenceMergeFailed(String callId) { 268 for (IConnectionServiceAdapter adapter : mAdapters) { 269 try { 270 Log.d(this, "merge failed for call %s", callId); 271 adapter.setConferenceMergeFailed(callId, Log.getExternalSession()); 272 } catch (RemoteException ignored) { 273 } 274 } 275 } 276 277 /** 278 * Resets the cdma connection time. 279 */ resetConnectionTime(String callId)280 void resetConnectionTime(String callId) { 281 for (IConnectionServiceAdapter adapter : mAdapters) { 282 try { 283 adapter.resetConnectionTime(callId, Log.getExternalSession()); 284 } catch (RemoteException e) { 285 } 286 } 287 } 288 289 /** 290 * Indicates that the call no longer exists. Can be used with either a call or a conference 291 * call. 292 * 293 * @param callId The unique ID of the call. 294 */ removeCall(String callId)295 void removeCall(String callId) { 296 for (IConnectionServiceAdapter adapter : mAdapters) { 297 try { 298 adapter.removeCall(callId, Log.getExternalSession()); 299 } catch (RemoteException ignored) { 300 } 301 } 302 } 303 onPostDialWait(String callId, String remaining)304 void onPostDialWait(String callId, String remaining) { 305 for (IConnectionServiceAdapter adapter : mAdapters) { 306 try { 307 adapter.onPostDialWait(callId, remaining, Log.getExternalSession()); 308 } catch (RemoteException ignored) { 309 } 310 } 311 } 312 onPostDialChar(String callId, char nextChar)313 void onPostDialChar(String callId, char nextChar) { 314 for (IConnectionServiceAdapter adapter : mAdapters) { 315 try { 316 adapter.onPostDialChar(callId, nextChar, Log.getExternalSession()); 317 } catch (RemoteException ignored) { 318 } 319 } 320 } 321 322 /** 323 * Indicates that a new conference call has been created. 324 * 325 * @param callId The unique ID of the conference call. 326 */ addConferenceCall(String callId, ParcelableConference parcelableConference)327 void addConferenceCall(String callId, ParcelableConference parcelableConference) { 328 for (IConnectionServiceAdapter adapter : mAdapters) { 329 try { 330 adapter.addConferenceCall(callId, parcelableConference, Log.getExternalSession()); 331 } catch (RemoteException ignored) { 332 } 333 } 334 } 335 336 /** 337 * Retrieves a list of remote connection services usable to place calls. 338 */ queryRemoteConnectionServices(RemoteServiceCallback callback, String callingPackage)339 void queryRemoteConnectionServices(RemoteServiceCallback callback, String callingPackage) { 340 // Only supported when there is only one adapter. 341 if (mAdapters.size() == 1) { 342 try { 343 mAdapters.iterator().next().queryRemoteConnectionServices(callback, callingPackage, 344 Log.getExternalSession()); 345 } catch (RemoteException e) { 346 Log.e(this, e, "Exception trying to query for remote CSs"); 347 } 348 } else { 349 try { 350 // This is not an error condition, so just pass back an empty list. 351 // This happens when querying from a remote connection service, not the connection 352 // manager itself. 353 callback.onResult(Collections.EMPTY_LIST, Collections.EMPTY_LIST); 354 } catch (RemoteException e) { 355 Log.e(this, e, "Exception trying to query for remote CSs"); 356 } 357 } 358 } 359 360 /** 361 * Sets the call video provider for a call. 362 * 363 * @param callId The unique ID of the call to set with the given call video provider. 364 * @param videoProvider The call video provider instance to set on the call. 365 */ setVideoProvider( String callId, Connection.VideoProvider videoProvider)366 void setVideoProvider( 367 String callId, Connection.VideoProvider videoProvider) { 368 for (IConnectionServiceAdapter adapter : mAdapters) { 369 try { 370 adapter.setVideoProvider( 371 callId, 372 videoProvider == null ? null : videoProvider.getInterface(), 373 Log.getExternalSession()); 374 } catch (RemoteException e) { 375 } 376 } 377 } 378 379 /** 380 * Requests that the framework use VOIP audio mode for this connection. 381 * 382 * @param callId The unique ID of the call to set with the given call video provider. 383 * @param isVoip True if the audio mode is VOIP. 384 */ setIsVoipAudioMode(String callId, boolean isVoip)385 void setIsVoipAudioMode(String callId, boolean isVoip) { 386 for (IConnectionServiceAdapter adapter : mAdapters) { 387 try { 388 adapter.setIsVoipAudioMode(callId, isVoip, Log.getExternalSession()); 389 } catch (RemoteException e) { 390 } 391 } 392 } 393 setStatusHints(String callId, StatusHints statusHints)394 void setStatusHints(String callId, StatusHints statusHints) { 395 for (IConnectionServiceAdapter adapter : mAdapters) { 396 try { 397 adapter.setStatusHints(callId, statusHints, Log.getExternalSession()); 398 } catch (RemoteException e) { 399 } 400 } 401 } 402 setAddress(String callId, Uri address, int presentation)403 void setAddress(String callId, Uri address, int presentation) { 404 for (IConnectionServiceAdapter adapter : mAdapters) { 405 try { 406 adapter.setAddress(callId, address, presentation, Log.getExternalSession()); 407 } catch (RemoteException e) { 408 } 409 } 410 } 411 setCallerDisplayName(String callId, String callerDisplayName, int presentation)412 void setCallerDisplayName(String callId, String callerDisplayName, int presentation) { 413 for (IConnectionServiceAdapter adapter : mAdapters) { 414 try { 415 adapter.setCallerDisplayName(callId, callerDisplayName, presentation, 416 Log.getExternalSession()); 417 } catch (RemoteException e) { 418 } 419 } 420 } 421 422 /** 423 * Sets the video state associated with a call. 424 * 425 * Valid values: {@link VideoProfile#STATE_BIDIRECTIONAL}, 426 * {@link VideoProfile#STATE_AUDIO_ONLY}, 427 * {@link VideoProfile#STATE_TX_ENABLED}, 428 * {@link VideoProfile#STATE_RX_ENABLED}. 429 * 430 * @param callId The unique ID of the call to set the video state for. 431 * @param videoState The video state. 432 */ setVideoState(String callId, int videoState)433 void setVideoState(String callId, int videoState) { 434 Log.v(this, "setVideoState: %d", videoState); 435 for (IConnectionServiceAdapter adapter : mAdapters) { 436 try { 437 adapter.setVideoState(callId, videoState, Log.getExternalSession()); 438 } catch (RemoteException ignored) { 439 } 440 } 441 } 442 setConferenceableConnections(String callId, List<String> conferenceableCallIds)443 void setConferenceableConnections(String callId, List<String> conferenceableCallIds) { 444 Log.v(this, "setConferenceableConnections: %s, %s", callId, conferenceableCallIds); 445 for (IConnectionServiceAdapter adapter : mAdapters) { 446 try { 447 adapter.setConferenceableConnections(callId, conferenceableCallIds, 448 Log.getExternalSession()); 449 } catch (RemoteException ignored) { 450 } 451 } 452 } 453 454 /** 455 * Informs telecom of an existing connection which was added by the {@link ConnectionService}. 456 * 457 * @param callId The unique ID of the call being added. 458 * @param connection The connection. 459 */ addExistingConnection(String callId, ParcelableConnection connection)460 void addExistingConnection(String callId, ParcelableConnection connection) { 461 Log.v(this, "addExistingConnection: %s", callId); 462 for (IConnectionServiceAdapter adapter : mAdapters) { 463 try { 464 adapter.addExistingConnection(callId, connection, Log.getExternalSession()); 465 } catch (RemoteException ignored) { 466 } 467 } 468 } 469 470 /** 471 * Adds some extras associated with a {@code Connection}. 472 * 473 * @param callId The unique ID of the call. 474 * @param extras The extras to add. 475 */ putExtras(String callId, Bundle extras)476 void putExtras(String callId, Bundle extras) { 477 Log.v(this, "putExtras: %s", callId); 478 for (IConnectionServiceAdapter adapter : mAdapters) { 479 try { 480 adapter.putExtras(callId, extras, Log.getExternalSession()); 481 } catch (RemoteException ignored) { 482 } 483 } 484 } 485 486 /** 487 * Adds an extra associated with a {@code Connection}. 488 * 489 * @param callId The unique ID of the call. 490 * @param key The extra key. 491 * @param value The extra value. 492 */ putExtra(String callId, String key, boolean value)493 void putExtra(String callId, String key, boolean value) { 494 Log.v(this, "putExtra: %s %s=%b", callId, key, value); 495 for (IConnectionServiceAdapter adapter : mAdapters) { 496 try { 497 Bundle bundle = new Bundle(); 498 bundle.putBoolean(key, value); 499 adapter.putExtras(callId, bundle, Log.getExternalSession()); 500 } catch (RemoteException ignored) { 501 } 502 } 503 } 504 505 /** 506 * Adds an extra associated with a {@code Connection}. 507 * 508 * @param callId The unique ID of the call. 509 * @param key The extra key. 510 * @param value The extra value. 511 */ putExtra(String callId, String key, int value)512 void putExtra(String callId, String key, int value) { 513 Log.v(this, "putExtra: %s %s=%d", callId, key, value); 514 for (IConnectionServiceAdapter adapter : mAdapters) { 515 try { 516 Bundle bundle = new Bundle(); 517 bundle.putInt(key, value); 518 adapter.putExtras(callId, bundle, Log.getExternalSession()); 519 } catch (RemoteException ignored) { 520 } 521 } 522 } 523 524 /** 525 * Adds an extra associated with a {@code Connection}. 526 * 527 * @param callId The unique ID of the call. 528 * @param key The extra key. 529 * @param value The extra value. 530 */ putExtra(String callId, String key, String value)531 void putExtra(String callId, String key, String value) { 532 Log.v(this, "putExtra: %s %s=%s", callId, key, value); 533 for (IConnectionServiceAdapter adapter : mAdapters) { 534 try { 535 Bundle bundle = new Bundle(); 536 bundle.putString(key, value); 537 adapter.putExtras(callId, bundle, Log.getExternalSession()); 538 } catch (RemoteException ignored) { 539 } 540 } 541 } 542 543 /** 544 * Removes extras associated with a {@code Connection}. 545 * @param callId The unique ID of the call. 546 * @param keys The extra keys to remove. 547 */ removeExtras(String callId, List<String> keys)548 void removeExtras(String callId, List<String> keys) { 549 Log.v(this, "removeExtras: %s %s", callId, keys); 550 for (IConnectionServiceAdapter adapter : mAdapters) { 551 try { 552 adapter.removeExtras(callId, keys, Log.getExternalSession()); 553 } catch (RemoteException ignored) { 554 } 555 } 556 } 557 558 /** 559 * Sets the audio route associated with a {@link Connection}. 560 * 561 * @param callId The unique ID of the call. 562 * @param audioRoute The new audio route (see {@code CallAudioState#ROUTE_*}). 563 */ setAudioRoute(String callId, int audioRoute, String bluetoothAddress)564 void setAudioRoute(String callId, int audioRoute, String bluetoothAddress) { 565 Log.v(this, "setAudioRoute: %s %s %s", callId, 566 CallAudioState.audioRouteToString(audioRoute), 567 bluetoothAddress); 568 for (IConnectionServiceAdapter adapter : mAdapters) { 569 try { 570 adapter.setAudioRoute(callId, audioRoute, 571 bluetoothAddress, Log.getExternalSession()); 572 } catch (RemoteException ignored) { 573 } 574 } 575 } 576 577 /** 578 * Sets the call endpoint associated with a {@link Connection}. 579 * 580 * @param callId The unique ID of the call. 581 * @param endpoint The new call endpoint (see {@link CallEndpoint}). 582 * @param executor The executor of where the callback will execute. 583 * @param callback The callback to notify the result of the endpoint change. 584 */ requestCallEndpointChange(String callId, CallEndpoint endpoint, Executor executor, OutcomeReceiver<Void, CallEndpointException> callback)585 void requestCallEndpointChange(String callId, CallEndpoint endpoint, Executor executor, 586 OutcomeReceiver<Void, CallEndpointException> callback) { 587 Log.v(this, "requestCallEndpointChange"); 588 for (IConnectionServiceAdapter adapter : mAdapters) { 589 try { 590 adapter.requestCallEndpointChange(callId, endpoint, new ResultReceiver(null) { 591 @Override 592 protected void onReceiveResult(int resultCode, Bundle result) { 593 super.onReceiveResult(resultCode, result); 594 final long identity = Binder.clearCallingIdentity(); 595 try { 596 if (resultCode == CallEndpoint.ENDPOINT_OPERATION_SUCCESS) { 597 executor.execute(() -> callback.onResult(null)); 598 } else { 599 executor.execute(() -> callback.onError(result.getParcelable( 600 CallEndpointException.CHANGE_ERROR, 601 CallEndpointException.class))); 602 } 603 } finally { 604 Binder.restoreCallingIdentity(identity); 605 } 606 }}, Log.getExternalSession()); 607 } catch (RemoteException ignored) { 608 Log.d(this, "Remote exception calling requestCallEndpointChange"); 609 } 610 } 611 } 612 613 /** 614 * Informs Telecom of a connection level event. 615 * 616 * @param callId The unique ID of the call. 617 * @param event The event. 618 * @param extras Extras associated with the event. 619 */ onConnectionEvent(String callId, String event, Bundle extras)620 void onConnectionEvent(String callId, String event, Bundle extras) { 621 Log.v(this, "onConnectionEvent: %s", event); 622 for (IConnectionServiceAdapter adapter : mAdapters) { 623 try { 624 adapter.onConnectionEvent(callId, event, extras, Log.getExternalSession()); 625 } catch (RemoteException ignored) { 626 } 627 } 628 } 629 630 /** 631 * Notifies Telecom that an RTT session was successfully established. 632 * 633 * @param callId The unique ID of the call. 634 */ onRttInitiationSuccess(String callId)635 void onRttInitiationSuccess(String callId) { 636 Log.v(this, "onRttInitiationSuccess: %s", callId); 637 for (IConnectionServiceAdapter adapter : mAdapters) { 638 try { 639 adapter.onRttInitiationSuccess(callId, Log.getExternalSession()); 640 } catch (RemoteException ignored) { 641 } 642 } 643 } 644 645 /** 646 * Notifies Telecom that a requested RTT session failed to be established. 647 * 648 * @param callId The unique ID of the call. 649 */ onRttInitiationFailure(String callId, int reason)650 void onRttInitiationFailure(String callId, int reason) { 651 Log.v(this, "onRttInitiationFailure: %s", callId); 652 for (IConnectionServiceAdapter adapter : mAdapters) { 653 try { 654 adapter.onRttInitiationFailure(callId, reason, Log.getExternalSession()); 655 } catch (RemoteException ignored) { 656 } 657 } 658 } 659 660 /** 661 * Notifies Telecom that an established RTT session was terminated by the remote user on 662 * the call. 663 * 664 * @param callId The unique ID of the call. 665 */ onRttSessionRemotelyTerminated(String callId)666 void onRttSessionRemotelyTerminated(String callId) { 667 Log.v(this, "onRttSessionRemotelyTerminated: %s", callId); 668 for (IConnectionServiceAdapter adapter : mAdapters) { 669 try { 670 adapter.onRttSessionRemotelyTerminated(callId, Log.getExternalSession()); 671 } catch (RemoteException ignored) { 672 } 673 } 674 } 675 676 /** 677 * Notifies Telecom that the remote user on the call has requested an upgrade to an RTT 678 * session for this call. 679 * 680 * @param callId The unique ID of the call. 681 */ onRemoteRttRequest(String callId)682 void onRemoteRttRequest(String callId) { 683 Log.v(this, "onRemoteRttRequest: %s", callId); 684 for (IConnectionServiceAdapter adapter : mAdapters) { 685 try { 686 adapter.onRemoteRttRequest(callId, Log.getExternalSession()); 687 } catch (RemoteException ignored) { 688 } 689 } 690 } 691 692 /** 693 * Notifies Telecom that a call's PhoneAccountHandle has changed. 694 * 695 * @param callId The unique ID of the call. 696 * @param pHandle The new PhoneAccountHandle associated with the call. 697 */ onPhoneAccountChanged(String callId, PhoneAccountHandle pHandle)698 void onPhoneAccountChanged(String callId, PhoneAccountHandle pHandle) { 699 for (IConnectionServiceAdapter adapter : mAdapters) { 700 try { 701 Log.d(this, "onPhoneAccountChanged %s", callId); 702 adapter.onPhoneAccountChanged(callId, pHandle, Log.getExternalSession()); 703 } catch (RemoteException ignored) { 704 } 705 } 706 } 707 708 /** 709 * Notifies Telecom that the {@link ConnectionService} has released the call resource. 710 */ onConnectionServiceFocusReleased()711 void onConnectionServiceFocusReleased() { 712 for (IConnectionServiceAdapter adapter : mAdapters) { 713 try { 714 Log.d(this, "onConnectionServiceFocusReleased"); 715 adapter.onConnectionServiceFocusReleased(Log.getExternalSession()); 716 } catch (RemoteException ignored) { 717 } 718 } 719 } 720 721 /** 722 * Sets whether a conference is treated as a conference or a single party call. 723 * See {@link Conference#setConferenceState(boolean)} for more information. 724 * 725 * @param callId The ID of the telecom call. 726 * @param isConference {@code true} if this call should be treated as a conference, 727 * {@code false} otherwise. 728 */ setConferenceState(String callId, boolean isConference)729 void setConferenceState(String callId, boolean isConference) { 730 Log.v(this, "setConferenceState: %s %b", callId, isConference); 731 for (IConnectionServiceAdapter adapter : mAdapters) { 732 try { 733 adapter.setConferenceState(callId, isConference, Log.getExternalSession()); 734 } catch (RemoteException ignored) { 735 } 736 } 737 } 738 739 /** 740 * Sets the direction of a call. Setting a new direction of an existing call is usually only 741 * applicable during single caller emulation during conferencing, see 742 * {@link Conference#setConferenceState(boolean)} for more information. 743 * @param callId The identifier of the call. 744 * @param direction The new direction of the call. 745 */ setCallDirection(String callId, @Call.Details.CallDirection int direction)746 void setCallDirection(String callId, @Call.Details.CallDirection int direction) { 747 for (IConnectionServiceAdapter a : mAdapters) { 748 try { 749 a.setCallDirection(callId, direction, Log.getExternalSession()); 750 } catch (RemoteException e) { 751 } 752 } 753 } 754 755 /** 756 * Query location information. 757 * Only SIM call managers can call this method for Connections representing Emergency calls. 758 * If the previous request is not completed, the new request will be rejected. 759 * 760 * @param timeoutMillis long: Timeout in millis waiting for query response. 761 * @param provider String: the location provider name, This value cannot be null. 762 * @param executor The executor of where the callback will execute. 763 * @param callback The callback to notify the result of queryLocation. 764 */ queryLocation(String callId, long timeoutMillis, @NonNull String provider, @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Location, QueryLocationException> callback)765 void queryLocation(String callId, long timeoutMillis, @NonNull String provider, 766 @NonNull @CallbackExecutor Executor executor, 767 @NonNull OutcomeReceiver<Location, QueryLocationException> callback) { 768 Log.v(this, "queryLocation: %s %d", callId, timeoutMillis); 769 for (IConnectionServiceAdapter adapter : mAdapters) { 770 try { 771 adapter.queryLocation(callId, timeoutMillis, provider, 772 new ResultReceiver(null) { 773 @Override 774 protected void onReceiveResult(int resultCode, Bundle result) { 775 super.onReceiveResult(resultCode, result); 776 777 if (resultCode == 1 /* success */) { 778 executor.execute(() -> callback.onResult(result.getParcelable( 779 Connection.EXTRA_KEY_QUERY_LOCATION, Location.class))); 780 } else { 781 executor.execute(() -> callback.onError(result.getParcelable( 782 QueryLocationException.QUERY_LOCATION_ERROR, 783 QueryLocationException.class))); 784 } 785 } 786 }, 787 Log.getExternalSession()); 788 } catch (RemoteException e) { 789 Log.d(this, "queryLocation: Exception e : " + e); 790 executor.execute(() -> callback.onError(new QueryLocationException( 791 e.getMessage(), QueryLocationException.ERROR_SERVICE_UNAVAILABLE))); 792 } 793 } 794 } 795 } 796