ConnectionServiceFixture.java revision b63b57e2c35c4769e756f47131c7ebbc0af42c59
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;
27import org.mockito.invocation.InvocationOnMock;
28import org.mockito.stubbing.Answer;
29
30import android.content.ComponentName;
31import android.os.IBinder;
32import android.os.RemoteException;
33import android.telecom.Connection;
34import android.telecom.ConnectionRequest;
35import android.telecom.DisconnectCause;
36import android.telecom.ParcelableConference;
37import android.telecom.ParcelableConnection;
38import android.telecom.PhoneAccountHandle;
39import android.telecom.StatusHints;
40
41import java.util.ArrayList;
42import java.util.HashMap;
43import java.util.HashSet;
44import java.util.List;
45import java.util.Map;
46import java.util.Set;
47
48import static org.mockito.Matchers.any;
49import static org.mockito.Matchers.anyString;
50import static org.mockito.Mockito.doAnswer;
51import static org.mockito.Mockito.when;
52
53/**
54 * Controls a test {@link IConnectionService} as would be provided by a source of connectivity
55 * to the Telecom framework.
56 */
57public class ConnectionServiceFixture implements TestFixture<IConnectionService> {
58
59    private IConnectionService.Stub mConnectionService =
60            Mockito.mock(IConnectionService.Stub.class);
61
62    public class ConnectionInfo {
63        PhoneAccountHandle connectionManagerPhoneAccount;
64        String id;
65        boolean ringing;
66        ConnectionRequest request;
67        boolean isIncoming;
68        boolean isUnknown;
69        int state;
70        int addressPresentation;
71        int capabilities;
72        StatusHints statusHints;
73        DisconnectCause disconnectCause;
74        String conferenceId;
75        String callerDisplayName;
76        int callerDisplayNamePresentation;
77        final List<String> conferenceableConnectionIds = new ArrayList<>();
78        IVideoProvider videoProvider;
79        int videoState;
80        boolean isVoipAudioMode;
81    }
82
83    public class ConferenceInfo {
84        PhoneAccountHandle phoneAccount;
85        int state;
86        int capabilities;
87        final List<String> connectionIds = new ArrayList<>();
88        long connectTimeMillis;
89    }
90
91    public String mLatestConnectionId;
92    public final Set<IConnectionServiceAdapter> mConnectionServiceAdapters = new HashSet<>();
93    public final Map<String, ConnectionInfo> mConnectionById = new HashMap<>();
94    public final Map<String, ConferenceInfo> mConferenceById = new HashMap<>();
95    public final List<ComponentName> mRemoteConnectionServiceNames = new ArrayList<>();
96    public final List<IBinder> mRemoteConnectionServices = new ArrayList<>();
97
98    public ConnectionServiceFixture() throws Exception {
99        doAnswer(new Answer<Object>() {
100            @Override
101            public Object answer(InvocationOnMock invocation) throws Throwable {
102                IConnectionServiceAdapter a = (IConnectionServiceAdapter)
103                        invocation.getArguments()[0];
104                if (!mConnectionServiceAdapters.add(a)) {
105                    throw new RuntimeException("Adapter already added: " + a);
106                }
107                return null;
108            }
109        }).when(mConnectionService).addConnectionServiceAdapter(
110                any(IConnectionServiceAdapter.class));
111
112        doAnswer(new Answer<Object>() {
113            @Override
114            public Object answer(InvocationOnMock invocation) throws Throwable {
115                IConnectionServiceAdapter a = (IConnectionServiceAdapter)
116                        invocation.getArguments()[0];
117                if (!mConnectionServiceAdapters.remove(a)) {
118                    throw new RuntimeException("Adapter never added: " + a);
119                }
120                return null;
121            }
122        }).when(mConnectionService).removeConnectionServiceAdapter(
123                any(IConnectionServiceAdapter.class));
124
125        doAnswer(new Answer<Object>() {
126            @Override
127            public Object answer(InvocationOnMock invocation) throws Throwable {
128                String id = (String) invocation.getArguments()[1];
129                if (mConnectionById.containsKey(id)) {
130                    throw new RuntimeException("Connection already exists: " + id);
131                }
132                mLatestConnectionId = id;
133                ConnectionInfo c = new ConnectionInfo();
134                c.connectionManagerPhoneAccount = (PhoneAccountHandle) invocation.getArguments()[0];
135                c.id = id;
136                c.request = (ConnectionRequest) invocation.getArguments()[2];
137                c.isIncoming = (boolean) invocation.getArguments()[3];
138                c.isUnknown = (boolean) invocation.getArguments()[4];
139                mConnectionById.put(id, c);
140                return null;
141            }
142        }).when(mConnectionService).createConnection(
143                any(PhoneAccountHandle.class),
144                any(String.class),
145                any(ConnectionRequest.class),
146                any(Boolean.TYPE),
147                any(Boolean.TYPE));
148
149        when(mConnectionService.asBinder())
150                .thenReturn(mConnectionService);
151        when(mConnectionService.queryLocalInterface(anyString()))
152                .thenReturn(mConnectionService);
153    }
154
155    @Override
156    public IConnectionService getTestDouble() {
157        return mConnectionService;
158    }
159
160    public void sendHandleCreateConnectionComplete(String id) throws Exception {
161        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
162            a.handleCreateConnectionComplete(
163                    id,
164                    mConnectionById.get(id).request,
165                    parcelable(mConnectionById.get(id)));
166        }
167    }
168
169    public void sendSetActive(String id) throws Exception {
170        mConnectionById.get(id).state = Connection.STATE_ACTIVE;
171        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
172            a.setActive(id);
173        }
174    }
175
176    public void sendSetRinging(String id) throws Exception {
177        mConnectionById.get(id).state = Connection.STATE_RINGING;
178        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
179            a.setRinging(id);
180        }
181    }
182
183    public void sendSetDialing(String id) throws Exception {
184        mConnectionById.get(id).state = Connection.STATE_DIALING;
185        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
186            a.setDialing(id);
187        }
188    }
189
190    public void sendSetDisconnected(String id, int disconnectCause) throws Exception {
191        mConnectionById.get(id).state = Connection.STATE_DISCONNECTED;
192        mConnectionById.get(id).disconnectCause = new DisconnectCause(disconnectCause);
193        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
194            a.setDisconnected(id, mConnectionById.get(id).disconnectCause);
195        }
196    }
197
198    public void sendSetOnHold(String id) throws Exception {
199        mConnectionById.get(id).state = Connection.STATE_HOLDING;
200        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
201            a.setOnHold(id);
202        }
203    }
204
205    public void sendSetRingbackRequested(String id) throws Exception {
206        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
207            a.setRingbackRequested(id, mConnectionById.get(id).ringing);
208        }
209    }
210
211    public void sendSetConnectionCapabilities(String id) throws Exception {
212        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
213            a.setConnectionCapabilities(id, mConnectionById.get(id).capabilities);
214        }
215    }
216
217    public void sendSetIsConferenced(String id) throws Exception {
218        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
219            a.setIsConferenced(id, mConnectionById.get(id).conferenceId);
220        }
221    }
222
223    public void sendAddConferenceCall(String id) throws Exception {
224        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
225            a.addConferenceCall(id, parcelable(mConferenceById.get(id)));
226        }
227    }
228
229    public void sendRemoveCall(String id) throws Exception {
230        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
231            a.removeCall(id);
232        }
233    }
234
235    public void sendOnPostDialWait(String id, String remaining) throws Exception {
236        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
237            a.onPostDialWait(id, remaining);
238        }
239    }
240
241    public void sendOnPostDialChar(String id, char nextChar) throws Exception {
242        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
243            a.onPostDialChar(id, nextChar);
244        }
245    }
246
247    public void sendQueryRemoteConnectionServices() throws Exception {
248        mRemoteConnectionServices.clear();
249        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
250            a.queryRemoteConnectionServices(new RemoteServiceCallback.Stub() {
251                @Override
252                public void onError() throws RemoteException {
253                    throw new RuntimeException();
254                }
255
256                @Override
257                public void onResult(
258                        List<ComponentName> names,
259                        List<IBinder> services)
260                        throws RemoteException {
261                    TestCase.assertEquals(names.size(), services.size());
262                    mRemoteConnectionServiceNames.addAll(names);
263                    mRemoteConnectionServices.addAll(services);
264                }
265
266                @Override
267                public IBinder asBinder() {
268                    return this;
269                }
270            });
271        }
272    }
273
274    public void sendSetVideoProvider(String id) throws Exception {
275        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
276            a.setVideoProvider(id, mConnectionById.get(id).videoProvider);
277        }
278    }
279
280    public void sendSetVideoState(String id) throws Exception {
281        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
282            a.setVideoState(id, mConnectionById.get(id).videoState);
283        }
284    }
285
286    public void sendSetIsVoipAudioMode(String id) throws Exception {
287        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
288            a.setIsVoipAudioMode(id, mConnectionById.get(id).isVoipAudioMode);
289        }
290    }
291
292    public void sendSetStatusHints(String id) throws Exception {
293        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
294            a.setStatusHints(id, mConnectionById.get(id).statusHints);
295        }
296    }
297
298    public void sendSetAddress(String id) throws Exception {
299        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
300            a.setAddress(
301                    id,
302                    mConnectionById.get(id).request.getAddress(),
303                    mConnectionById.get(id).addressPresentation);
304        }
305    }
306
307    public void sendSetCallerDisplayName(String id) throws Exception {
308        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
309            a.setCallerDisplayName(
310                    id,
311                    mConnectionById.get(id).callerDisplayName,
312                    mConnectionById.get(id).callerDisplayNamePresentation);
313        }
314    }
315
316    public void sendSetConferenceableConnections(String id) throws Exception {
317        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
318            a.setConferenceableConnections(id, mConnectionById.get(id).conferenceableConnectionIds);
319        }
320    }
321
322    public void sendAddExistingConnection(String id) throws Exception {
323        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
324            a.addExistingConnection(id, parcelable(mConnectionById.get(id)));
325        }
326    }
327
328    private ParcelableConference parcelable(ConferenceInfo c) {
329        return new ParcelableConference(
330                c.phoneAccount,
331                c.state,
332                c.capabilities,
333                c.connectionIds,
334                c.connectTimeMillis);
335    }
336
337    private ParcelableConnection parcelable(ConnectionInfo c) {
338        return new ParcelableConnection(
339                c.request.getAccountHandle(),
340                c.state,
341                c.capabilities,
342                c.request.getAddress(),
343                c.addressPresentation,
344                c.callerDisplayName,
345                c.callerDisplayNamePresentation,
346                c.videoProvider,
347                c.videoState,
348                false, /* ringback requested */
349                false, /* voip audio mode */
350                c.statusHints,
351                c.disconnectCause,
352                c.conferenceableConnectionIds);
353    }
354}
355