1 /* 2 * Copyright (C) 2015 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.tests; 18 19 import com.android.internal.telecom.IConnectionService; 20 import com.android.internal.telecom.IConnectionServiceAdapter; 21 import com.android.internal.telecom.IVideoProvider; 22 import com.android.internal.telecom.RemoteServiceCallback; 23 24 import junit.framework.TestCase; 25 26 import org.mockito.Mockito; 27 28 import android.content.ComponentName; 29 import android.content.Context; 30 import android.net.Uri; 31 import android.os.Bundle; 32 import android.os.IBinder; 33 import android.os.IInterface; 34 import android.os.ParcelFileDescriptor; 35 import android.os.RemoteException; 36 import android.telecom.CallAudioState; 37 import android.telecom.Conference; 38 import android.telecom.Connection; 39 import android.telecom.ConnectionRequest; 40 import android.telecom.ConnectionService; 41 import android.telecom.DisconnectCause; 42 import android.telecom.Log; 43 import android.telecom.Logging.Session; 44 import android.telecom.ParcelableConference; 45 import android.telecom.ParcelableConnection; 46 import android.telecom.PhoneAccountHandle; 47 import android.telecom.StatusHints; 48 import android.telecom.TelecomManager; 49 50 import com.google.android.collect.Lists; 51 52 import java.lang.Override; 53 import java.util.ArrayList; 54 import java.util.HashMap; 55 import java.util.HashSet; 56 import java.util.List; 57 import java.util.Map; 58 import java.util.Set; 59 import java.util.concurrent.CountDownLatch; 60 import java.util.concurrent.TimeUnit; 61 62 /** 63 * Controls a test {@link IConnectionService} as would be provided by a source of connectivity 64 * to the Telecom framework. 65 */ 66 public class ConnectionServiceFixture implements TestFixture<IConnectionService> { 67 static int INVALID_VIDEO_STATE = -1; 68 public CountDownLatch mExtrasLock = new CountDownLatch(1); 69 static int NOT_SPECIFIED = 0; 70 71 /** 72 * Implementation of ConnectionService that performs no-ops for tasks normally meant for 73 * Telephony and reports success back to Telecom 74 */ 75 public class FakeConnectionServiceDelegate extends ConnectionService { 76 int mVideoState = INVALID_VIDEO_STATE; 77 int mCapabilities = NOT_SPECIFIED; 78 int mProperties = NOT_SPECIFIED; 79 FakeConnectionServiceDelegate(Context base)80 public FakeConnectionServiceDelegate(Context base) { 81 attachBaseContext(base); 82 } 83 84 @Override onCreateUnknownConnection( PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request)85 public Connection onCreateUnknownConnection( 86 PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) { 87 mLatestConnection = new FakeConnection(request.getVideoState(), request.getAddress()); 88 return mLatestConnection; 89 } 90 91 @Override onCreateIncomingConnection( PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request)92 public Connection onCreateIncomingConnection( 93 PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) { 94 FakeConnection fakeConnection = new FakeConnection( 95 mVideoState == INVALID_VIDEO_STATE ? request.getVideoState() : mVideoState, 96 request.getAddress()); 97 mLatestConnection = fakeConnection; 98 if (mCapabilities != NOT_SPECIFIED) { 99 fakeConnection.setConnectionCapabilities(mCapabilities); 100 } 101 if (mProperties != NOT_SPECIFIED) { 102 fakeConnection.setConnectionProperties(mProperties); 103 } 104 105 return fakeConnection; 106 } 107 108 @Override onCreateOutgoingConnection( PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request)109 public Connection onCreateOutgoingConnection( 110 PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) { 111 FakeConnection fakeConnection = new FakeConnection(request.getVideoState(), 112 request.getAddress()); 113 mLatestConnection = fakeConnection; 114 if (mCapabilities != NOT_SPECIFIED) { 115 fakeConnection.setConnectionCapabilities(mCapabilities); 116 } 117 if (mProperties != NOT_SPECIFIED) { 118 fakeConnection.setConnectionProperties(mProperties); 119 } 120 return fakeConnection; 121 } 122 123 @Override onCreateConnectionComplete(Connection connection)124 public void onCreateConnectionComplete(Connection connection) { 125 } 126 127 @Override onConference(Connection cxn1, Connection cxn2)128 public void onConference(Connection cxn1, Connection cxn2) { 129 if (((FakeConnection) cxn1).getIsConferenceCreated()) { 130 // Usually, this is implemented by something in Telephony, which does a bunch of 131 // radio work to conference the two connections together. Here we just short-cut 132 // that and declare them conferenced. 133 Conference fakeConference = new FakeConference(); 134 fakeConference.addConnection(cxn1); 135 fakeConference.addConnection(cxn2); 136 mLatestConference = fakeConference; 137 addConference(fakeConference); 138 } else { 139 try { 140 sendSetConferenceMergeFailed(cxn1.getTelecomCallId()); 141 } catch (Exception e) { 142 Log.w(this, "Exception on sendSetConferenceMergeFailed: " + e.getMessage()); 143 } 144 } 145 } 146 } 147 148 public class FakeConnection extends Connection { 149 // Set to false if you wish the Conference merge to fail. 150 boolean mIsConferenceCreated = true; 151 FakeConnection(int videoState, Uri address)152 public FakeConnection(int videoState, Uri address) { 153 super(); 154 int capabilities = getConnectionCapabilities(); 155 capabilities |= CAPABILITY_MUTE; 156 capabilities |= CAPABILITY_SUPPORT_HOLD; 157 capabilities |= CAPABILITY_HOLD; 158 setVideoState(videoState); 159 setConnectionCapabilities(capabilities); 160 setDialing(); 161 setAddress(address, TelecomManager.PRESENTATION_ALLOWED); 162 } 163 164 @Override onExtrasChanged(Bundle extras)165 public void onExtrasChanged(Bundle extras) { 166 mExtrasLock.countDown(); 167 } 168 getIsConferenceCreated()169 public boolean getIsConferenceCreated() { 170 return mIsConferenceCreated; 171 } 172 setIsConferenceCreated(boolean isConferenceCreated)173 public void setIsConferenceCreated(boolean isConferenceCreated) { 174 mIsConferenceCreated = isConferenceCreated; 175 } 176 } 177 178 public class FakeConference extends Conference { FakeConference()179 public FakeConference() { 180 super(null); 181 setConnectionCapabilities( 182 Connection.CAPABILITY_SUPPORT_HOLD 183 | Connection.CAPABILITY_HOLD 184 | Connection.CAPABILITY_MUTE 185 | Connection.CAPABILITY_MANAGE_CONFERENCE); 186 } 187 188 @Override onMerge(Connection connection)189 public void onMerge(Connection connection) { 190 // Do nothing besides inform the connection that it was merged into this conference. 191 connection.setConference(this); 192 } 193 194 @Override onExtrasChanged(Bundle extras)195 public void onExtrasChanged(Bundle extras) { 196 Log.w(this, "FakeConference onExtrasChanged"); 197 mExtrasLock.countDown(); 198 } 199 } 200 201 public class FakeConnectionService extends IConnectionService.Stub { 202 List<String> rejectedCallIds = Lists.newArrayList(); 203 204 @Override addConnectionServiceAdapter(IConnectionServiceAdapter adapter, Session.Info info)205 public void addConnectionServiceAdapter(IConnectionServiceAdapter adapter, 206 Session.Info info) throws RemoteException { 207 if (!mConnectionServiceAdapters.add(adapter)) { 208 throw new RuntimeException("Adapter already added: " + adapter); 209 } 210 mConnectionServiceDelegateAdapter.addConnectionServiceAdapter(adapter, 211 null /*Session.Info*/); 212 } 213 214 @Override removeConnectionServiceAdapter(IConnectionServiceAdapter adapter, Session.Info info)215 public void removeConnectionServiceAdapter(IConnectionServiceAdapter adapter, 216 Session.Info info) throws RemoteException { 217 if (!mConnectionServiceAdapters.remove(adapter)) { 218 throw new RuntimeException("Adapter never added: " + adapter); 219 } 220 mConnectionServiceDelegateAdapter.removeConnectionServiceAdapter(adapter, 221 null /*Session.Info*/); 222 } 223 224 @Override createConnection(PhoneAccountHandle connectionManagerPhoneAccount, String id, ConnectionRequest request, boolean isIncoming, boolean isUnknown, Session.Info info)225 public void createConnection(PhoneAccountHandle connectionManagerPhoneAccount, 226 String id, ConnectionRequest request, boolean isIncoming, boolean isUnknown, 227 Session.Info info) throws RemoteException { 228 Log.i(ConnectionServiceFixture.this, "createConnection --> " + id); 229 230 if (mConnectionById.containsKey(id)) { 231 throw new RuntimeException("Connection already exists: " + id); 232 } 233 mLatestConnectionId = id; 234 ConnectionInfo c = new ConnectionInfo(); 235 c.connectionManagerPhoneAccount = connectionManagerPhoneAccount; 236 c.id = id; 237 c.request = request; 238 c.isIncoming = isIncoming; 239 c.isUnknown = isUnknown; 240 c.capabilities |= Connection.CAPABILITY_HOLD | Connection.CAPABILITY_SUPPORT_HOLD; 241 c.videoState = request.getVideoState(); 242 c.mockVideoProvider = new MockVideoProvider(); 243 c.videoProvider = c.mockVideoProvider.getInterface(); 244 c.isConferenceCreated = true; 245 mConnectionById.put(id, c); 246 mConnectionServiceDelegateAdapter.createConnection(connectionManagerPhoneAccount, 247 id, request, isIncoming, isUnknown, null /*Session.Info*/); 248 } 249 250 @Override createConnectionComplete(String id, Session.Info info)251 public void createConnectionComplete(String id, Session.Info info) throws RemoteException { 252 mConnectionServiceDelegateAdapter.createConnectionComplete(id, null /*Session.Info*/); 253 } 254 255 @Override createConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount, String callId, ConnectionRequest request, boolean isIncoming, Session.Info sessionInfo)256 public void createConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount, 257 String callId, ConnectionRequest request, boolean isIncoming, 258 Session.Info sessionInfo) throws RemoteException { 259 Log.i(ConnectionServiceFixture.this, "createConnectionFailed --> " + callId); 260 261 if (mConnectionById.containsKey(callId)) { 262 throw new RuntimeException("Connection already exists: " + callId); 263 } 264 265 // TODO(3p-calls): Implement this. 266 } 267 268 @Override createConference( PhoneAccountHandle connectionManagerPhoneAccount, String id, ConnectionRequest request, boolean isIncoming, boolean isUnknown, Session.Info sessionInfo)269 public void createConference( 270 PhoneAccountHandle connectionManagerPhoneAccount, 271 String id, 272 ConnectionRequest request, 273 boolean isIncoming, 274 boolean isUnknown, 275 Session.Info sessionInfo) { } 276 277 @Override createConferenceComplete(String id, Session.Info sessionInfo)278 public void createConferenceComplete(String id, Session.Info sessionInfo) { } 279 280 @Override createConferenceFailed( PhoneAccountHandle connectionManagerPhoneAccount, String callId, ConnectionRequest request, boolean isIncoming, Session.Info sessionInfo)281 public void createConferenceFailed( 282 PhoneAccountHandle connectionManagerPhoneAccount, 283 String callId, 284 ConnectionRequest request, 285 boolean isIncoming, 286 Session.Info sessionInfo) { } 287 288 @Override abort(String callId, Session.Info info)289 public void abort(String callId, Session.Info info) throws RemoteException { } 290 291 @Override answerVideo(String callId, int videoState, Session.Info info)292 public void answerVideo(String callId, int videoState, 293 Session.Info info) throws RemoteException { } 294 295 @Override answer(String callId, Session.Info info)296 public void answer(String callId, Session.Info info) throws RemoteException { } 297 298 @Override deflect(String callId, Uri address, Session.Info info)299 public void deflect(String callId, Uri address, Session.Info info) 300 throws RemoteException { } 301 302 @Override transfer(String callId, Uri number, boolean isConfirmationRequired, Session.Info info)303 public void transfer(String callId, Uri number, boolean isConfirmationRequired, 304 Session.Info info) throws RemoteException { } 305 306 @Override consultativeTransfer(String callId, String otherCallId, Session.Info info)307 public void consultativeTransfer(String callId, String otherCallId, 308 Session.Info info) throws RemoteException { } 309 310 @Override reject(String callId, Session.Info info)311 public void reject(String callId, Session.Info info) throws RemoteException { 312 rejectedCallIds.add(callId); 313 } 314 rejectWithReason(java.lang.String callId, int rejectReason, android.telecom.Logging.Session.Info sessionInfo)315 @Override public void rejectWithReason(java.lang.String callId, int rejectReason, 316 android.telecom.Logging.Session.Info sessionInfo) throws RemoteException { 317 rejectedCallIds.add(callId); 318 } 319 320 @Override rejectWithMessage(String callId, String message, Session.Info info)321 public void rejectWithMessage(String callId, String message, 322 Session.Info info) throws RemoteException { 323 rejectedCallIds.add(callId); 324 } 325 326 @Override disconnect(String callId, Session.Info info)327 public void disconnect(String callId, Session.Info info) throws RemoteException { } 328 329 @Override silence(String callId, Session.Info info)330 public void silence(String callId, Session.Info info) throws RemoteException { } 331 332 @Override hold(String callId, Session.Info info)333 public void hold(String callId, Session.Info info) throws RemoteException { } 334 335 @Override unhold(String callId, Session.Info info)336 public void unhold(String callId, Session.Info info) throws RemoteException { } 337 338 @Override onCallAudioStateChanged(String activeCallId, CallAudioState audioState, Session.Info info)339 public void onCallAudioStateChanged(String activeCallId, CallAudioState audioState, 340 Session.Info info) 341 throws RemoteException { } 342 343 @Override playDtmfTone(String callId, char digit, Session.Info info)344 public void playDtmfTone(String callId, char digit, 345 Session.Info info) throws RemoteException { } 346 347 @Override stopDtmfTone(String callId, Session.Info info)348 public void stopDtmfTone(String callId, Session.Info info) throws RemoteException { } 349 350 @Override conference(String conferenceCallId, String callId, Session.Info info)351 public void conference(String conferenceCallId, String callId, 352 Session.Info info) throws RemoteException { 353 mConnectionServiceDelegateAdapter.conference(conferenceCallId, callId, info); 354 } 355 356 @Override splitFromConference(String callId, Session.Info info)357 public void splitFromConference(String callId, Session.Info info) throws RemoteException { } 358 359 @Override mergeConference(String conferenceCallId, Session.Info info)360 public void mergeConference(String conferenceCallId, 361 Session.Info info) throws RemoteException { } 362 363 @Override swapConference(String conferenceCallId, Session.Info info)364 public void swapConference(String conferenceCallId, 365 Session.Info info) throws RemoteException { } 366 367 @Override addConferenceParticipants(String CallId, List<Uri> participants, Session.Info sessionInfo)368 public void addConferenceParticipants(String CallId, List<Uri> participants, 369 Session.Info sessionInfo) throws RemoteException { 370 371 } 372 373 @Override onPostDialContinue(String callId, boolean proceed, Session.Info info)374 public void onPostDialContinue(String callId, boolean proceed, 375 Session.Info info) throws RemoteException { } 376 377 @Override pullExternalCall(String callId, Session.Info info)378 public void pullExternalCall(String callId, Session.Info info) throws RemoteException { } 379 380 @Override sendCallEvent(String callId, String event, Bundle extras, Session.Info info)381 public void sendCallEvent(String callId, String event, Bundle extras, 382 Session.Info info) throws RemoteException 383 {} 384 onExtrasChanged(String callId, Bundle extras, Session.Info info)385 public void onExtrasChanged(String callId, Bundle extras, 386 Session.Info info) throws RemoteException { 387 mConnectionServiceDelegateAdapter.onExtrasChanged(callId, extras, info); 388 } 389 390 @Override startRtt(String callId, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall, Session.Info sessionInfo)391 public void startRtt(String callId, ParcelFileDescriptor fromInCall, 392 ParcelFileDescriptor toInCall, Session.Info sessionInfo) throws RemoteException { 393 394 } 395 396 @Override stopRtt(String callId, Session.Info sessionInfo)397 public void stopRtt(String callId, Session.Info sessionInfo) throws RemoteException { 398 399 } 400 401 @Override respondToRttUpgradeRequest(String callId, ParcelFileDescriptor fromInCall, ParcelFileDescriptor toInCall, Session.Info sessionInfo)402 public void respondToRttUpgradeRequest(String callId, ParcelFileDescriptor fromInCall, 403 ParcelFileDescriptor toInCall, Session.Info sessionInfo) throws RemoteException { 404 405 } 406 407 @Override connectionServiceFocusLost(Session.Info sessionInfo)408 public void connectionServiceFocusLost(Session.Info sessionInfo) throws RemoteException { 409 } 410 411 @Override connectionServiceFocusGained(Session.Info sessionInfo)412 public void connectionServiceFocusGained(Session.Info sessionInfo) throws RemoteException { 413 } 414 415 @Override asBinder()416 public IBinder asBinder() { 417 return this; 418 } 419 420 @Override queryLocalInterface(String descriptor)421 public IInterface queryLocalInterface(String descriptor) { 422 return this; 423 } 424 425 @Override handoverFailed(String callId, ConnectionRequest request, int error, Session.Info sessionInfo)426 public void handoverFailed(String callId, ConnectionRequest request, 427 int error, Session.Info sessionInfo) {} 428 429 @Override handoverComplete(String callId, Session.Info sessionInfo)430 public void handoverComplete(String callId, Session.Info sessionInfo) {} 431 } 432 433 FakeConnectionServiceDelegate mConnectionServiceDelegate; 434 private IConnectionService mConnectionServiceDelegateAdapter; 435 436 FakeConnectionService mConnectionService = new FakeConnectionService(); 437 private IConnectionService.Stub mConnectionServiceSpy = Mockito.spy(mConnectionService); 438 439 public class ConnectionInfo { 440 PhoneAccountHandle connectionManagerPhoneAccount; 441 String id; 442 boolean ringing; 443 ConnectionRequest request; 444 boolean isIncoming; 445 boolean isUnknown; 446 int state; 447 int addressPresentation; 448 int capabilities; 449 int properties; 450 int supportedAudioRoutes; 451 StatusHints statusHints; 452 DisconnectCause disconnectCause; 453 String conferenceId; 454 String callerDisplayName; 455 int callerDisplayNamePresentation; 456 final List<String> conferenceableConnectionIds = new ArrayList<>(); 457 IVideoProvider videoProvider; 458 Connection.VideoProvider videoProviderImpl; 459 MockVideoProvider mockVideoProvider; 460 int videoState; 461 boolean isVoipAudioMode; 462 Bundle extras; 463 boolean isConferenceCreated; 464 int callerNumberVerificationStatus; 465 } 466 467 public class ConferenceInfo { 468 PhoneAccountHandle phoneAccount; 469 int state; 470 int capabilities; 471 int properties; 472 final List<String> connectionIds = new ArrayList<>(); 473 IVideoProvider videoProvider; 474 int videoState; 475 long connectTimeMillis; 476 long connectElapsedTimeMillis; 477 StatusHints statusHints; 478 Bundle extras; 479 } 480 481 public String mLatestConnectionId; 482 public Connection mLatestConnection; 483 public Conference mLatestConference; 484 public final Set<IConnectionServiceAdapter> mConnectionServiceAdapters = new HashSet<>(); 485 public final Map<String, ConnectionInfo> mConnectionById = new HashMap<>(); 486 public final Map<String, ConferenceInfo> mConferenceById = new HashMap<>(); 487 public final List<ComponentName> mRemoteConnectionServiceNames = new ArrayList<>(); 488 public final List<IBinder> mRemoteConnectionServices = new ArrayList<>(); 489 ConnectionServiceFixture(Context context)490 public ConnectionServiceFixture(Context context) throws Exception { 491 mConnectionServiceDelegate = new FakeConnectionServiceDelegate(context); 492 mConnectionServiceDelegateAdapter = IConnectionService.Stub.asInterface( 493 mConnectionServiceDelegate.onBind(null)); 494 } 495 496 @Override getTestDouble()497 public IConnectionService getTestDouble() { 498 return mConnectionServiceSpy; 499 } 500 sendHandleCreateConnectionComplete(String id)501 public void sendHandleCreateConnectionComplete(String id) throws Exception { 502 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 503 a.handleCreateConnectionComplete( 504 id, 505 mConnectionById.get(id).request, 506 parcelable(mConnectionById.get(id)), null /*Session.Info*/); 507 } 508 } 509 sendSetActive(String id)510 public void sendSetActive(String id) throws Exception { 511 mConnectionById.get(id).state = Connection.STATE_ACTIVE; 512 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 513 a.setActive(id, null /*Session.Info*/); 514 } 515 } 516 sendSetRinging(String id)517 public void sendSetRinging(String id) throws Exception { 518 mConnectionById.get(id).state = Connection.STATE_RINGING; 519 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 520 a.setRinging(id, null /*Session.Info*/); 521 } 522 } 523 sendSetDialing(String id)524 public void sendSetDialing(String id) throws Exception { 525 mConnectionById.get(id).state = Connection.STATE_DIALING; 526 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 527 a.setDialing(id, null /*Session.Info*/); 528 } 529 } 530 sendSetDisconnected(String id, int disconnectCause)531 public void sendSetDisconnected(String id, int disconnectCause) throws Exception { 532 mConnectionById.get(id).state = Connection.STATE_DISCONNECTED; 533 mConnectionById.get(id).disconnectCause = new DisconnectCause(disconnectCause); 534 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 535 a.setDisconnected(id, mConnectionById.get(id).disconnectCause, null /*Session.Info*/); 536 } 537 } 538 sendSetOnHold(String id)539 public void sendSetOnHold(String id) throws Exception { 540 mConnectionById.get(id).state = Connection.STATE_HOLDING; 541 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 542 a.setOnHold(id, null /*Session.Info*/); 543 } 544 } 545 sendSetRingbackRequested(String id)546 public void sendSetRingbackRequested(String id) throws Exception { 547 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 548 a.setRingbackRequested(id, mConnectionById.get(id).ringing, null /*Session.Info*/); 549 } 550 } 551 sendSetConnectionCapabilities(String id)552 public void sendSetConnectionCapabilities(String id) throws Exception { 553 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 554 a.setConnectionCapabilities(id, mConnectionById.get(id).capabilities, 555 null /*Session.Info*/); 556 } 557 } 558 sendSetConnectionProperties(String id)559 public void sendSetConnectionProperties(String id) throws Exception { 560 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 561 a.setConnectionProperties(id, mConnectionById.get(id).properties, null /*Session.Info*/); 562 } 563 } sendSetIsConferenced(String id)564 public void sendSetIsConferenced(String id) throws Exception { 565 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 566 a.setIsConferenced(id, mConnectionById.get(id).conferenceId, null /*Session.Info*/); 567 } 568 } 569 sendAddConferenceCall(String id)570 public void sendAddConferenceCall(String id) throws Exception { 571 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 572 a.addConferenceCall(id, parcelable(mConferenceById.get(id)), null /*Session.Info*/); 573 } 574 } 575 sendRemoveCall(String id)576 public void sendRemoveCall(String id) throws Exception { 577 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 578 a.removeCall(id, null /*Session.Info*/); 579 } 580 } 581 sendOnPostDialWait(String id, String remaining)582 public void sendOnPostDialWait(String id, String remaining) throws Exception { 583 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 584 a.onPostDialWait(id, remaining, null /*Session.Info*/); 585 } 586 } 587 sendOnPostDialChar(String id, char nextChar)588 public void sendOnPostDialChar(String id, char nextChar) throws Exception { 589 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 590 a.onPostDialChar(id, nextChar, null /*Session.Info*/); 591 } 592 } 593 sendQueryRemoteConnectionServices()594 public void sendQueryRemoteConnectionServices() throws Exception { 595 mRemoteConnectionServices.clear(); 596 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 597 a.queryRemoteConnectionServices(new RemoteServiceCallback.Stub() { 598 @Override 599 public void onError() throws RemoteException { 600 throw new RuntimeException(); 601 } 602 603 @Override 604 public void onResult( 605 List<ComponentName> names, 606 List<IBinder> services) 607 throws RemoteException { 608 TestCase.assertEquals(names.size(), services.size()); 609 mRemoteConnectionServiceNames.addAll(names); 610 mRemoteConnectionServices.addAll(services); 611 } 612 613 @Override 614 public IBinder asBinder() { 615 return this; 616 } 617 }, "" /* callingPackage */, null /*Session.Info*/); 618 } 619 } 620 sendSetVideoProvider(String id)621 public void sendSetVideoProvider(String id) throws Exception { 622 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 623 a.setVideoProvider(id, mConnectionById.get(id).videoProvider, null /*Session.Info*/); 624 } 625 } 626 sendSetVideoState(String id)627 public void sendSetVideoState(String id) throws Exception { 628 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 629 a.setVideoState(id, mConnectionById.get(id).videoState, null /*Session.Info*/); 630 } 631 } 632 sendSetIsVoipAudioMode(String id)633 public void sendSetIsVoipAudioMode(String id) throws Exception { 634 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 635 a.setIsVoipAudioMode(id, mConnectionById.get(id).isVoipAudioMode, 636 null /*Session.Info*/); 637 } 638 } 639 sendSetStatusHints(String id)640 public void sendSetStatusHints(String id) throws Exception { 641 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 642 a.setStatusHints(id, mConnectionById.get(id).statusHints, null /*Session.Info*/); 643 } 644 } 645 sendSetAddress(String id)646 public void sendSetAddress(String id) throws Exception { 647 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 648 a.setAddress( 649 id, 650 mConnectionById.get(id).request.getAddress(), 651 mConnectionById.get(id).addressPresentation, null /*Session.Info*/); 652 } 653 } 654 sendSetCallerDisplayName(String id)655 public void sendSetCallerDisplayName(String id) throws Exception { 656 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 657 a.setCallerDisplayName( 658 id, 659 mConnectionById.get(id).callerDisplayName, 660 mConnectionById.get(id).callerDisplayNamePresentation, null /*Session.Info*/); 661 } 662 } 663 sendSetConferenceableConnections(String id)664 public void sendSetConferenceableConnections(String id) throws Exception { 665 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 666 a.setConferenceableConnections(id, mConnectionById.get(id).conferenceableConnectionIds, 667 null /*Session.Info*/); 668 } 669 } 670 sendAddExistingConnection(String id)671 public void sendAddExistingConnection(String id) throws Exception { 672 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 673 a.addExistingConnection(id, parcelable(mConnectionById.get(id)), null /*Session.Info*/); 674 } 675 } 676 sendConnectionEvent(String id, String event, Bundle extras)677 public void sendConnectionEvent(String id, String event, Bundle extras) throws Exception { 678 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 679 a.onConnectionEvent(id, event, extras, null /*Session.Info*/); 680 } 681 } 682 sendSetConferenceMergeFailed(String id)683 public void sendSetConferenceMergeFailed(String id) throws Exception { 684 for (IConnectionServiceAdapter a : mConnectionServiceAdapters) { 685 a.setConferenceMergeFailed(id, null /*Session.Info*/); 686 } 687 } 688 689 /** 690 * Waits until the {@link Connection#onExtrasChanged(Bundle)} API has been called on a 691 * {@link Connection} or {@link Conference}. 692 */ waitForExtras()693 public void waitForExtras() { 694 try { 695 mExtrasLock.await(TelecomSystemTest.TEST_TIMEOUT, TimeUnit.MILLISECONDS); 696 } catch (InterruptedException ie) { 697 } 698 mExtrasLock = new CountDownLatch(1); 699 } 700 waitForHandlerToClear()701 public void waitForHandlerToClear() { 702 mConnectionServiceDelegate.getHandler().removeCallbacksAndMessages(null); 703 final CountDownLatch lock = new CountDownLatch(1); 704 mConnectionServiceDelegate.getHandler().post(lock::countDown); 705 while (lock.getCount() > 0) { 706 try { 707 lock.await(TelecomSystemTest.TEST_TIMEOUT, TimeUnit.MILLISECONDS); 708 } catch (InterruptedException e) { 709 // do nothing 710 } 711 } 712 } 713 parcelable(ConferenceInfo c)714 private ParcelableConference parcelable(ConferenceInfo c) { 715 return new ParcelableConference.Builder(c.phoneAccount, c.state) 716 .setConnectionCapabilities(c.capabilities) 717 .setConnectionProperties(c.properties) 718 .setConnectionIds(c.connectionIds) 719 .setVideoAttributes(c.videoProvider, c.videoState) 720 .setConnectTimeMillis(c.connectTimeMillis, c.connectElapsedTimeMillis) 721 .setStatusHints(c.statusHints) 722 .setExtras(c.extras) 723 .build(); 724 } 725 parcelable(ConnectionInfo c)726 private ParcelableConnection parcelable(ConnectionInfo c) { 727 return new ParcelableConnection( 728 c.request.getAccountHandle(), 729 c.state, 730 c.capabilities, 731 c.properties, 732 c.supportedAudioRoutes, 733 c.request.getAddress(), 734 c.addressPresentation, 735 c.callerDisplayName, 736 c.callerDisplayNamePresentation, 737 c.videoProvider, 738 c.videoState, 739 false, /* ringback requested */ 740 false, /* voip audio mode */ 741 0, /* Connect Time for conf call on this connection */ 742 0, /* Connect Real Time comes from conference call */ 743 c.statusHints, 744 c.disconnectCause, 745 c.conferenceableConnectionIds, 746 c.extras, 747 c.callerNumberVerificationStatus); 748 } 749 } 750