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