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