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
17package com.android.server.telecom.tests;
18
19import com.android.internal.telecom.IConnectionService;
20import com.android.internal.telecom.IConnectionServiceAdapter;
21import com.android.internal.telecom.IVideoProvider;
22import com.android.internal.telecom.RemoteServiceCallback;
23
24import junit.framework.TestCase;
25
26import org.mockito.Mockito;
27
28import android.content.ComponentName;
29import android.content.Context;
30import android.net.Uri;
31import android.os.Bundle;
32import android.os.IBinder;
33import android.os.IInterface;
34import android.os.ParcelFileDescriptor;
35import android.os.RemoteException;
36import android.telecom.CallAudioState;
37import android.telecom.Conference;
38import android.telecom.Connection;
39import android.telecom.ConnectionRequest;
40import android.telecom.ConnectionService;
41import android.telecom.DisconnectCause;
42import android.telecom.Log;
43import android.telecom.Logging.Session;
44import android.telecom.ParcelableConference;
45import android.telecom.ParcelableConnection;
46import android.telecom.PhoneAccountHandle;
47import android.telecom.StatusHints;
48import android.telecom.TelecomManager;
49
50import com.google.android.collect.Lists;
51
52import java.lang.Override;
53import java.util.ArrayList;
54import java.util.HashMap;
55import java.util.HashSet;
56import java.util.List;
57import java.util.Map;
58import java.util.Set;
59import java.util.concurrent.CountDownLatch;
60import 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 */
66public 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