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