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