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