Home | History | Annotate | Download | only in tests
      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 
     80         public FakeConnectionServiceDelegate(Context base) {
     81             attachBaseContext(base);
     82         }
     83 
     84         @Override
     85         public Connection onCreateUnknownConnection(
     86                 PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) {
     87             mLatestConnection = new FakeConnection(request.getVideoState(), request.getAddress());
     88             return mLatestConnection;
     89         }
     90 
     91         @Override
     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
    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
    124         public void onCreateConnectionComplete(Connection connection) {
    125         }
    126 
    127         @Override
    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 
    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
    165         public void onExtrasChanged(Bundle extras) {
    166             mExtrasLock.countDown();
    167         }
    168 
    169         public boolean getIsConferenceCreated() {
    170             return mIsConferenceCreated;
    171         }
    172 
    173         public void setIsConferenceCreated(boolean isConferenceCreated) {
    174             mIsConferenceCreated = isConferenceCreated;
    175         }
    176     }
    177 
    178     public class FakeConference extends Conference {
    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
    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
    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
    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
    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
    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
    251         public void createConnectionComplete(String id, Session.Info info) throws RemoteException {
    252             mConnectionServiceDelegateAdapter.createConnectionComplete(id, null /*Session.Info*/);
    253         }
    254 
    255         @Override
    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
    269         public void abort(String callId, Session.Info info) throws RemoteException { }
    270 
    271         @Override
    272         public void answerVideo(String callId, int videoState,
    273                 Session.Info info) throws RemoteException { }
    274 
    275         @Override
    276         public void answer(String callId, Session.Info info) throws RemoteException { }
    277 
    278         @Override
    279         public void deflect(String callId, Uri address, Session.Info info)
    280                 throws RemoteException { }
    281 
    282         @Override
    283         public void reject(String callId, Session.Info info) throws RemoteException {
    284             rejectedCallIds.add(callId);
    285         }
    286 
    287         @Override
    288         public void rejectWithMessage(String callId, String message,
    289                 Session.Info info) throws RemoteException { }
    290 
    291         @Override
    292         public void disconnect(String callId, Session.Info info) throws RemoteException { }
    293 
    294         @Override
    295         public void silence(String callId, Session.Info info) throws RemoteException { }
    296 
    297         @Override
    298         public void hold(String callId, Session.Info info) throws RemoteException { }
    299 
    300         @Override
    301         public void unhold(String callId, Session.Info info) throws RemoteException { }
    302 
    303         @Override
    304         public void onCallAudioStateChanged(String activeCallId, CallAudioState audioState,
    305                 Session.Info info)
    306                 throws RemoteException { }
    307 
    308         @Override
    309         public void playDtmfTone(String callId, char digit,
    310                 Session.Info info) throws RemoteException { }
    311 
    312         @Override
    313         public void stopDtmfTone(String callId, Session.Info info) throws RemoteException { }
    314 
    315         @Override
    316         public void conference(String conferenceCallId, String callId,
    317                 Session.Info info) throws RemoteException {
    318             mConnectionServiceDelegateAdapter.conference(conferenceCallId, callId, info);
    319         }
    320 
    321         @Override
    322         public void splitFromConference(String callId, Session.Info info) throws RemoteException { }
    323 
    324         @Override
    325         public void mergeConference(String conferenceCallId,
    326                 Session.Info info) throws RemoteException { }
    327 
    328         @Override
    329         public void swapConference(String conferenceCallId,
    330                 Session.Info info) throws RemoteException { }
    331 
    332         @Override
    333         public void onPostDialContinue(String callId, boolean proceed,
    334                 Session.Info info) throws RemoteException { }
    335 
    336         @Override
    337         public void pullExternalCall(String callId, Session.Info info) throws RemoteException { }
    338 
    339         @Override
    340         public void sendCallEvent(String callId, String event, Bundle extras,
    341                 Session.Info info) throws RemoteException
    342         {}
    343 
    344         public void onExtrasChanged(String callId, Bundle extras,
    345                 Session.Info info) throws RemoteException {
    346             mConnectionServiceDelegateAdapter.onExtrasChanged(callId, extras, info);
    347         }
    348 
    349         @Override
    350         public void startRtt(String callId, ParcelFileDescriptor fromInCall,
    351                 ParcelFileDescriptor toInCall, Session.Info sessionInfo) throws RemoteException {
    352 
    353         }
    354 
    355         @Override
    356         public void stopRtt(String callId, Session.Info sessionInfo) throws RemoteException {
    357 
    358         }
    359 
    360         @Override
    361         public void respondToRttUpgradeRequest(String callId, ParcelFileDescriptor fromInCall,
    362                 ParcelFileDescriptor toInCall, Session.Info sessionInfo) throws RemoteException {
    363 
    364         }
    365 
    366         @Override
    367         public void connectionServiceFocusLost(Session.Info sessionInfo) throws RemoteException {
    368         }
    369 
    370         @Override
    371         public void connectionServiceFocusGained(Session.Info sessionInfo) throws RemoteException {
    372         }
    373 
    374         @Override
    375         public IBinder asBinder() {
    376             return this;
    377         }
    378 
    379         @Override
    380         public IInterface queryLocalInterface(String descriptor) {
    381             return this;
    382         }
    383 
    384         @Override
    385         public void handoverFailed(String callId, ConnectionRequest request,
    386                                    int error, Session.Info sessionInfo) {}
    387 
    388         @Override
    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 
    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
    455     public IConnectionService getTestDouble() {
    456         return mConnectionServiceSpy;
    457     }
    458 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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     }
    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 
    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 
    534     public void sendRemoveCall(String id) throws Exception {
    535         for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
    536             a.removeCall(id, null /*Session.Info*/);
    537         }
    538     }
    539 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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      */
    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 
    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 
    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