PhoneAccountRegistrarTest.java revision aa383cca668afd8578a6e007c3ea360768dc52f6
1/*
2 * Copyright (C) 2014 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 android.annotation.TargetApi;
20import android.os.Binder;
21
22import com.android.internal.telecom.IConnectionService;
23import com.android.internal.util.FastXmlSerializer;
24import com.android.server.telecom.Log;
25import com.android.server.telecom.PhoneAccountRegistrar;
26
27import org.mockito.Mockito;
28import org.xmlpull.v1.XmlPullParser;
29import org.xmlpull.v1.XmlSerializer;
30
31import android.content.ComponentName;
32import android.content.Context;
33import android.graphics.Bitmap;
34import android.graphics.BitmapFactory;
35import android.net.Uri;
36import android.os.Parcel;
37import android.telecom.PhoneAccount;
38import android.telecom.PhoneAccountHandle;
39import android.util.Xml;
40
41import java.io.BufferedInputStream;
42import java.io.BufferedOutputStream;
43import java.io.ByteArrayInputStream;
44import java.io.ByteArrayOutputStream;
45import java.io.File;
46import java.util.Arrays;
47
48public class PhoneAccountRegistrarTest extends TelecomTestCase {
49
50    private static final int MAX_VERSION = Integer.MAX_VALUE;
51    private static final String FILE_NAME = "phone-account-registrar-test-1223.xml";
52    private PhoneAccountRegistrar mRegistrar;
53
54    @Override
55    public void setUp() throws Exception {
56        super.setUp();
57        mComponentContextFixture = new ComponentContextFixture();
58        new File(
59                mComponentContextFixture.getTestDouble().getApplicationContext().getFilesDir(),
60                FILE_NAME)
61                .delete();
62        mRegistrar = new PhoneAccountRegistrar(
63                mComponentContextFixture.getTestDouble().getApplicationContext(),
64                FILE_NAME);
65    }
66
67    @Override
68    public void tearDown() throws Exception {
69        mRegistrar = null;
70        mComponentContextFixture = null;
71        new File(
72                mComponentContextFixture.getTestDouble().getApplicationContext().getFilesDir(),
73                FILE_NAME)
74                .delete();
75        super.tearDown();
76    }
77
78    public void testPhoneAccountHandle() throws Exception {
79        PhoneAccountHandle input = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id0");
80        PhoneAccountHandle result = roundTripXml(this, input,
81                PhoneAccountRegistrar.sPhoneAccountHandleXml, mContext);
82        assertPhoneAccountHandleEquals(input, result);
83
84        PhoneAccountHandle inputN = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), null);
85        PhoneAccountHandle resultN = roundTripXml(this, inputN,
86                PhoneAccountRegistrar.sPhoneAccountHandleXml, mContext);
87        Log.i(this, "inputN = %s, resultN = %s", inputN, resultN);
88        assertPhoneAccountHandleEquals(inputN, resultN);
89    }
90
91    public void testPhoneAccount() throws Exception {
92        PhoneAccount input = makeQuickAccountBuilder("id0", 0)
93                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
94                .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
95                .build();
96        PhoneAccount result = roundTripXml(this, input, PhoneAccountRegistrar.sPhoneAccountXml,
97                mContext);
98        assertPhoneAccountEquals(input, result);
99    }
100
101    public void testState() throws Exception {
102        PhoneAccountRegistrar.State input = makeQuickState();
103        PhoneAccountRegistrar.State result = roundTripXml(this, input,
104                PhoneAccountRegistrar.sStateXml,
105                mContext);
106        assertStateEquals(input, result);
107    }
108
109    public void testAccounts() throws Exception {
110        int i = 0;
111
112        mComponentContextFixture.addConnectionService(
113                makeQuickConnectionServiceComponentName(),
114                Mockito.mock(IConnectionService.class));
115
116        mRegistrar.registerPhoneAccount(makeQuickAccountBuilder("id" + i, i++)
117                .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER
118                        | PhoneAccount.CAPABILITY_CALL_PROVIDER)
119                .build());
120        mRegistrar.registerPhoneAccount(makeQuickAccountBuilder("id" + i, i++)
121                .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER
122                        | PhoneAccount.CAPABILITY_CALL_PROVIDER)
123                .build());
124        mRegistrar.registerPhoneAccount(makeQuickAccountBuilder("id" + i, i++)
125                .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER
126                        | PhoneAccount.CAPABILITY_CALL_PROVIDER)
127                .build());
128        mRegistrar.registerPhoneAccount(makeQuickAccountBuilder("id" + i, i++)
129                .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
130                .build());
131
132        assertEquals(4, mRegistrar.getAllPhoneAccountHandles().size());
133        assertEquals(3, mRegistrar.getCallCapablePhoneAccounts().size());
134        assertEquals(null, mRegistrar.getSimCallManager());
135        assertEquals(null, mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL));
136    }
137
138    public void testSimCallManager() throws Exception {
139        mComponentContextFixture.addConnectionService(
140                makeQuickConnectionServiceComponentName(),
141                Mockito.mock(IConnectionService.class));
142
143        PhoneAccountHandle simManager = makeQuickAccountHandle("sim_mgr");
144        PhoneAccount simManagerAccount = new PhoneAccount.Builder(simManager, "sim_mgr")
145                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER
146                        | PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
147                .build();
148        mRegistrar.registerPhoneAccount(simManagerAccount);
149        assertNull(mRegistrar.getSimCallManager());
150
151        // Test the basic case
152        mRegistrar.setSimCallManager(simManager);
153        assertEquals(simManager, mRegistrar.getSimCallManager());
154
155        // Make sure clearing it works, too
156        mRegistrar.unregisterPhoneAccount(simManager);
157        assertNull(mRegistrar.getSimCallManager());
158
159        // Re-registering it makes the setting come back
160        mRegistrar.registerPhoneAccount(simManagerAccount);
161        assertEquals(simManager, mRegistrar.getSimCallManager());
162
163        // Make sure that the manager has CAPABILITY_CONNECTION_MANAGER
164        PhoneAccountHandle simManagerImposter = makeQuickAccountHandle("imposter");
165        PhoneAccount simManagerImposterAccount =
166                new PhoneAccount.Builder(simManagerImposter, "imposter")
167                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
168                .build();
169        mRegistrar.registerPhoneAccount(simManagerImposterAccount);
170
171        mRegistrar.setSimCallManager(null);
172        assertNull(mRegistrar.getSimCallManager());
173        mRegistrar.setSimCallManager(simManagerImposter);
174        assertNull(mRegistrar.getSimCallManager());
175    }
176
177    public void testDefaultOutgoing() throws Exception {
178        mComponentContextFixture.addConnectionService(
179                makeQuickConnectionServiceComponentName(),
180                Mockito.mock(IConnectionService.class));
181
182        // By default, there is no default outgoing account (nothing has been registered)
183        assertNull(mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL));
184
185        // Register one tel: account
186        PhoneAccountHandle telAccount = makeQuickAccountHandle("tel_acct");
187        mRegistrar.registerPhoneAccount(new PhoneAccount.Builder(telAccount, "tel_acct")
188                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
189                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
190                .build());
191        PhoneAccountHandle defaultAccount =
192                mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL);
193        assertEquals(telAccount, defaultAccount);
194
195        // Add a SIP account, make sure tel: doesn't change
196        PhoneAccountHandle sipAccount = makeQuickAccountHandle("sip_acct");
197        mRegistrar.registerPhoneAccount(new PhoneAccount.Builder(sipAccount, "sip_acct")
198                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
199                .addSupportedUriScheme(PhoneAccount.SCHEME_SIP)
200                .build());
201        defaultAccount = mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_SIP);
202        assertEquals(sipAccount, defaultAccount);
203        defaultAccount = mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL);
204        assertEquals(telAccount, defaultAccount);
205
206        // Add a connection manager, make sure tel: doesn't change
207        PhoneAccountHandle connectionManager = makeQuickAccountHandle("mgr_acct");
208        mRegistrar.registerPhoneAccount(new PhoneAccount.Builder(connectionManager, "mgr_acct")
209                .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
210                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
211                .build());
212        defaultAccount = mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL);
213        assertEquals(telAccount, defaultAccount);
214
215        // Unregister the tel: account, make sure there is no tel: default now.
216        mRegistrar.unregisterPhoneAccount(telAccount);
217        assertNull(mRegistrar.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL));
218    }
219
220    public void testPhoneAccountParceling() throws Exception {
221        PhoneAccountHandle handle = makeQuickAccountHandle("foo");
222        roundTripPhoneAccount(new PhoneAccount.Builder(handle, null).build());
223        roundTripPhoneAccount(new PhoneAccount.Builder(handle, "foo").build());
224        roundTripPhoneAccount(
225                new PhoneAccount.Builder(handle, "foo")
226                        .setAddress(Uri.parse("tel:123456"))
227                        .setCapabilities(23)
228                        .setHighlightColor(0xf0f0f0)
229                        .setIcon(
230                                "com.android.server.telecom.tests",
231                                R.drawable.stat_sys_phone_call,
232                                0xfefefe)
233                        .setShortDescription("short description")
234                        .setSubscriptionAddress(Uri.parse("tel:2345678"))
235                        .setSupportedUriSchemes(Arrays.asList("tel", "sip"))
236                        .build());
237        roundTripPhoneAccount(
238                new PhoneAccount.Builder(handle, "foo")
239                        .setAddress(Uri.parse("tel:123456"))
240                        .setCapabilities(23)
241                        .setHighlightColor(0xf0f0f0)
242                        .setIcon(
243                                BitmapFactory.decodeResource(
244                                        getContext().getResources(),
245                                        R.drawable.stat_sys_phone_call))
246                        .setShortDescription("short description")
247                        .setSubscriptionAddress(Uri.parse("tel:2345678"))
248                        .setSupportedUriSchemes(Arrays.asList("tel", "sip"))
249                        .build());
250    }
251
252    private static ComponentName makeQuickConnectionServiceComponentName() {
253        return new ComponentName(
254                "com.android.server.telecom.tests",
255                "com.android.server.telecom.tests.MockConnectionService");
256    }
257
258    private static PhoneAccountHandle makeQuickAccountHandle(String id) {
259        return new PhoneAccountHandle(
260                makeQuickConnectionServiceComponentName(),
261                id,
262                Binder.getCallingUserHandle());
263    }
264
265    private PhoneAccount.Builder makeQuickAccountBuilder(String id, int idx) {
266        return new PhoneAccount.Builder(
267                makeQuickAccountHandle(id),
268                "label" + idx);
269    }
270
271    private PhoneAccount makeQuickAccount(String id, int idx) {
272        return makeQuickAccountBuilder(id, idx)
273                .setAddress(Uri.parse("http://foo.com/" + idx))
274                .setSubscriptionAddress(Uri.parse("tel:555-000" + idx))
275                .setCapabilities(idx)
276                .setIcon("com.android.server.telecom.tests", R.drawable.stat_sys_phone_call)
277                .setShortDescription("desc" + idx)
278                .build();
279    }
280
281    private static void roundTripPhoneAccount(PhoneAccount original) throws Exception {
282        PhoneAccount copy = null;
283
284        {
285            Parcel parcel = Parcel.obtain();
286            parcel.writeParcelable(original, 0);
287            parcel.setDataPosition(0);
288            copy = parcel.readParcelable(PhoneAccountRegistrarTest.class.getClassLoader());
289            parcel.recycle();
290        }
291
292        assertPhoneAccountEquals(original, copy);
293    }
294
295    private static <T> T roundTripXml(
296            Object self,
297            T input,
298            PhoneAccountRegistrar.XmlSerialization<T> xml,
299            Context context)
300            throws Exception {
301        Log.d(self, "Input = %s", input);
302
303        byte[] data;
304        {
305            XmlSerializer serializer = new FastXmlSerializer();
306            ByteArrayOutputStream baos = new ByteArrayOutputStream();
307            serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
308            xml.writeToXml(input, serializer, context);
309            serializer.flush();
310            data = baos.toByteArray();
311        }
312
313        Log.d(self, "====== XML data ======\n%s", new String(data));
314
315        T result = null;
316        {
317            XmlPullParser parser = Xml.newPullParser();
318            parser.setInput(new BufferedInputStream(new ByteArrayInputStream(data)), null);
319            parser.nextTag();
320            result = xml.readFromXml(parser, MAX_VERSION, context);
321        }
322
323        Log.d(self, "result = " + result);
324
325        return result;
326    }
327
328    private static void assertPhoneAccountHandleEquals(PhoneAccountHandle a, PhoneAccountHandle b) {
329        if (a != b) {
330            assertEquals(
331                    a.getComponentName().getPackageName(),
332                    b.getComponentName().getPackageName());
333            assertEquals(
334                    a.getComponentName().getClassName(),
335                    b.getComponentName().getClassName());
336            assertEquals(a.getId(), b.getId());
337        }
338    }
339
340    private static void assertPhoneAccountEquals(PhoneAccount a, PhoneAccount b) {
341        if (a != b) {
342            assertPhoneAccountHandleEquals(a.getAccountHandle(), b.getAccountHandle());
343            assertEquals(a.getAddress(), b.getAddress());
344            assertEquals(a.getSubscriptionAddress(), b.getSubscriptionAddress());
345            assertEquals(a.getCapabilities(), b.getCapabilities());
346            assertEquals(a.getIconResId(), b.getIconResId());
347            assertEquals(a.getIconPackageName(), b.getIconPackageName());
348            assertBitmapEquals(a.getIconBitmap(), b.getIconBitmap());
349            assertEquals(a.getIconTint(), b.getIconTint());
350            assertEquals(a.getHighlightColor(), b.getHighlightColor());
351            assertEquals(a.getLabel(), b.getLabel());
352            assertEquals(a.getShortDescription(), b.getShortDescription());
353            assertEquals(a.getSupportedUriSchemes(), b.getSupportedUriSchemes());
354        }
355    }
356
357    private static void assertBitmapEquals(Bitmap a, Bitmap b) {
358        if (a == null || b == null) {
359            assertEquals(null, a);
360            assertEquals(null, b);
361        } else {
362            assertEquals(a.getWidth(), b.getWidth());
363            assertEquals(a.getHeight(), b.getHeight());
364            for (int x = 0; x < a.getWidth(); x++) {
365                for (int y = 0; y < a.getHeight(); y++) {
366                    assertEquals(a.getPixel(x, y), b.getPixel(x, y));
367                }
368            }
369        }
370    }
371
372    private static void assertStateEquals(
373            PhoneAccountRegistrar.State a, PhoneAccountRegistrar.State b) {
374        assertPhoneAccountHandleEquals(a.defaultOutgoing, b.defaultOutgoing);
375        assertPhoneAccountHandleEquals(a.simCallManager, b.simCallManager);
376        assertEquals(a.accounts.size(), b.accounts.size());
377        for (int i = 0; i < a.accounts.size(); i++) {
378            assertPhoneAccountEquals(a.accounts.get(i), b.accounts.get(i));
379        }
380    }
381
382    private PhoneAccountRegistrar.State makeQuickState() {
383        PhoneAccountRegistrar.State s = new PhoneAccountRegistrar.State();
384        s.accounts.add(makeQuickAccount("id0", 0));
385        s.accounts.add(makeQuickAccount("id1", 1));
386        s.accounts.add(makeQuickAccount("id2", 2));
387        s.defaultOutgoing = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id0");
388        s.simCallManager = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id1");
389        return s;
390    }
391}
392