• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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