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