PhoneAccountRegistrarTest.java revision ded880cfb3f6bc2e49465b3d2d5f9fa639b045f5
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.content.ComponentName;
20import android.content.Context;
21import android.graphics.BitmapFactory;
22import android.graphics.Rect;
23import android.graphics.drawable.Icon;
24import android.net.Uri;
25import android.os.Bundle;
26import android.os.Parcel;
27import android.os.Process;
28import android.os.UserHandle;
29import android.telecom.Log;
30import android.telecom.PhoneAccount;
31import android.telecom.PhoneAccountHandle;
32import android.telecom.TelecomManager;
33import android.test.suitebuilder.annotation.MediumTest;
34import android.util.Xml;
35
36import com.android.internal.telecom.IConnectionService;
37import com.android.internal.util.FastXmlSerializer;
38import com.android.server.telecom.DefaultDialerCache;
39import com.android.server.telecom.PhoneAccountRegistrar;
40import com.android.server.telecom.PhoneAccountRegistrar.DefaultPhoneAccountHandle;
41
42import org.mockito.Mock;
43import org.mockito.Mockito;
44import org.mockito.MockitoAnnotations;
45import org.xmlpull.v1.XmlPullParser;
46import org.xmlpull.v1.XmlSerializer;
47
48import java.io.BufferedInputStream;
49import java.io.BufferedOutputStream;
50import java.io.ByteArrayInputStream;
51import java.io.ByteArrayOutputStream;
52import java.io.File;
53import java.util.Arrays;
54import java.util.Set;
55
56import static org.mockito.Matchers.anyInt;
57import static org.mockito.Mockito.when;
58
59public class PhoneAccountRegistrarTest extends TelecomTestCase {
60
61    private static final int MAX_VERSION = Integer.MAX_VALUE;
62    private static final String FILE_NAME = "phone-account-registrar-test-1223.xml";
63    private PhoneAccountRegistrar mRegistrar;
64    @Mock private TelecomManager mTelecomManager;
65    @Mock private DefaultDialerCache mDefaultDialerCache;
66
67    @Override
68    public void setUp() throws Exception {
69        super.setUp();
70        MockitoAnnotations.initMocks(this);
71        mComponentContextFixture.setTelecomManager(mTelecomManager);
72        new File(
73                mComponentContextFixture.getTestDouble().getApplicationContext().getFilesDir(),
74                FILE_NAME)
75                .delete();
76        when(mDefaultDialerCache.getDefaultDialerApplication(anyInt()))
77                .thenReturn("com.android.dialer");
78        mRegistrar = new PhoneAccountRegistrar(
79                mComponentContextFixture.getTestDouble().getApplicationContext(),
80                FILE_NAME, mDefaultDialerCache);
81    }
82
83    @Override
84    public void tearDown() throws Exception {
85        mRegistrar = null;
86        new File(
87                mComponentContextFixture.getTestDouble().getApplicationContext().getFilesDir(),
88                FILE_NAME)
89                .delete();
90        super.tearDown();
91    }
92
93    @MediumTest
94    public void testPhoneAccountHandle() throws Exception {
95        PhoneAccountHandle input = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id0");
96        PhoneAccountHandle result = roundTripXml(this, input,
97                PhoneAccountRegistrar.sPhoneAccountHandleXml, mContext);
98        assertPhoneAccountHandleEquals(input, result);
99
100        PhoneAccountHandle inputN = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), null);
101        PhoneAccountHandle resultN = roundTripXml(this, inputN,
102                PhoneAccountRegistrar.sPhoneAccountHandleXml, mContext);
103        Log.i(this, "inputN = %s, resultN = %s", inputN, resultN);
104        assertPhoneAccountHandleEquals(inputN, resultN);
105    }
106
107    @MediumTest
108    public void testPhoneAccount() throws Exception {
109        Bundle testBundle = new Bundle();
110        testBundle.putInt("EXTRA_INT_1", 1);
111        testBundle.putInt("EXTRA_INT_100", 100);
112        testBundle.putBoolean("EXTRA_BOOL_TRUE", true);
113        testBundle.putBoolean("EXTRA_BOOL_FALSE", false);
114        testBundle.putString("EXTRA_STR1", "Hello");
115        testBundle.putString("EXTRA_STR2", "There");
116
117        PhoneAccount input = makeQuickAccountBuilder("id0", 0)
118                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
119                .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
120                .setExtras(testBundle)
121                .setIsEnabled(true)
122                .build();
123        PhoneAccount result = roundTripXml(this, input, PhoneAccountRegistrar.sPhoneAccountXml,
124                mContext);
125
126        assertPhoneAccountEquals(input, result);
127    }
128
129    @MediumTest
130    public void testDefaultPhoneAccountHandleEmptyGroup() throws Exception {
131        DefaultPhoneAccountHandle input = new DefaultPhoneAccountHandle(Process.myUserHandle(),
132                makeQuickAccountHandle("i1"), "");
133        DefaultPhoneAccountHandle result = roundTripXml(this, input,
134                PhoneAccountRegistrar.sDefaultPhoneAcountHandleXml, mContext);
135
136        assertDefaultPhoneAccountHandleEquals(input, result);
137    }
138
139    /**
140     * Test to ensure non-supported values
141     * @throws Exception
142     */
143    @MediumTest
144    public void testPhoneAccountExtrasEdge() throws Exception {
145        Bundle testBundle = new Bundle();
146        // Ensure null values for string are not persisted.
147        testBundle.putString("EXTRA_STR2", null);
148        //
149
150        // Ensure unsupported data types are not persisted.
151        testBundle.putShort("EXTRA_SHORT", (short) 2);
152        testBundle.putByte("EXTRA_BYTE", (byte) 1);
153        testBundle.putParcelable("EXTRA_PARC", new Rect(1, 1, 1, 1));
154        // Put in something valid so the bundle exists.
155        testBundle.putString("EXTRA_OK", "OK");
156
157        PhoneAccount input = makeQuickAccountBuilder("id0", 0)
158                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
159                .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
160                .setExtras(testBundle)
161                .build();
162        PhoneAccount result = roundTripXml(this, input, PhoneAccountRegistrar.sPhoneAccountXml,
163                mContext);
164
165        Bundle extras = result.getExtras();
166        assertFalse(extras.keySet().contains("EXTRA_STR2"));
167        assertFalse(extras.keySet().contains("EXTRA_SHORT"));
168        assertFalse(extras.keySet().contains("EXTRA_BYTE"));
169        assertFalse(extras.keySet().contains("EXTRA_PARC"));
170    }
171
172    @MediumTest
173    public void testState() throws Exception {
174        PhoneAccountRegistrar.State input = makeQuickState();
175        PhoneAccountRegistrar.State result = roundTripXml(this, input,
176                PhoneAccountRegistrar.sStateXml,
177                mContext);
178        assertStateEquals(input, result);
179    }
180
181    private void registerAndEnableAccount(PhoneAccount account) {
182        mRegistrar.registerPhoneAccount(account);
183        mRegistrar.enablePhoneAccount(account.getAccountHandle(), true);
184    }
185
186    @MediumTest
187    public void testAccounts() throws Exception {
188        int i = 0;
189
190        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
191                Mockito.mock(IConnectionService.class));
192
193        registerAndEnableAccount(makeQuickAccountBuilder("id" + i, i++)
194                .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER
195                        | PhoneAccount.CAPABILITY_CALL_PROVIDER)
196                .build());
197        registerAndEnableAccount(makeQuickAccountBuilder("id" + i, i++)
198                .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER
199                        | PhoneAccount.CAPABILITY_CALL_PROVIDER)
200                .build());
201        registerAndEnableAccount(makeQuickAccountBuilder("id" + i, i++)
202                .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER
203                        | PhoneAccount.CAPABILITY_CALL_PROVIDER)
204                .build());
205        registerAndEnableAccount(makeQuickAccountBuilder("id" + i, i++)
206                .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
207                .build());
208
209        assertEquals(4, mRegistrar.getAllPhoneAccountsOfCurrentUser().size());
210        assertEquals(3, mRegistrar.getCallCapablePhoneAccountsOfCurrentUser(null, false).size());
211        assertEquals(null, mRegistrar.getSimCallManagerOfCurrentUser());
212        assertEquals(null, mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
213                PhoneAccount.SCHEME_TEL));
214    }
215
216    @MediumTest
217    public void testSimCallManager() throws Exception {
218        // TODO
219    }
220
221    @MediumTest
222    public void testDefaultOutgoing() throws Exception {
223        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
224                Mockito.mock(IConnectionService.class));
225
226        // By default, there is no default outgoing account (nothing has been registered)
227        assertNull(
228                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL));
229
230        // Register one tel: account
231        PhoneAccountHandle telAccount = makeQuickAccountHandle("tel_acct");
232        registerAndEnableAccount(new PhoneAccount.Builder(telAccount, "tel_acct")
233                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
234                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
235                .build());
236        PhoneAccountHandle defaultAccount =
237                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL);
238        assertEquals(telAccount, defaultAccount);
239
240        // Add a SIP account, make sure tel: doesn't change
241        PhoneAccountHandle sipAccount = makeQuickAccountHandle("sip_acct");
242        registerAndEnableAccount(new PhoneAccount.Builder(sipAccount, "sip_acct")
243                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
244                .addSupportedUriScheme(PhoneAccount.SCHEME_SIP)
245                .build());
246        defaultAccount = mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
247                PhoneAccount.SCHEME_SIP);
248        assertEquals(sipAccount, defaultAccount);
249        defaultAccount = mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
250                PhoneAccount.SCHEME_TEL);
251        assertEquals(telAccount, defaultAccount);
252
253        // Add a connection manager, make sure tel: doesn't change
254        PhoneAccountHandle connectionManager = makeQuickAccountHandle("mgr_acct");
255        registerAndEnableAccount(new PhoneAccount.Builder(connectionManager, "mgr_acct")
256                .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
257                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
258                .build());
259        defaultAccount = mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
260                PhoneAccount.SCHEME_TEL);
261        assertEquals(telAccount, defaultAccount);
262
263        // Unregister the tel: account, make sure there is no tel: default now.
264        mRegistrar.unregisterPhoneAccount(telAccount);
265        assertNull(
266                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL));
267    }
268
269    @MediumTest
270    public void testReplacePhoneAccountByGroup() throws Exception {
271        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
272                Mockito.mock(IConnectionService.class));
273
274        // By default, there is no default outgoing account (nothing has been registered)
275        assertNull(
276                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL));
277
278        // Register one tel: account
279        PhoneAccountHandle telAccount1 = makeQuickAccountHandle("tel_acct1");
280        registerAndEnableAccount(new PhoneAccount.Builder(telAccount1, "tel_acct1")
281                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
282                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
283                .setGroupId("testGroup")
284                .build());
285        mRegistrar.setUserSelectedOutgoingPhoneAccount(telAccount1, Process.myUserHandle());
286        PhoneAccountHandle defaultAccount =
287                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL);
288        assertEquals(telAccount1, defaultAccount);
289
290        // Add call capable SIP account, make sure tel: doesn't change
291        PhoneAccountHandle sipAccount = makeQuickAccountHandle("sip_acct");
292        registerAndEnableAccount(new PhoneAccount.Builder(sipAccount, "sip_acct")
293                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
294                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
295                .build());
296        defaultAccount = mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
297                PhoneAccount.SCHEME_TEL);
298        assertEquals(telAccount1, defaultAccount);
299
300        // Replace tel: account with another in the same Group
301        PhoneAccountHandle telAccount2 = makeQuickAccountHandle("tel_acct2");
302        registerAndEnableAccount(new PhoneAccount.Builder(telAccount2, "tel_acct2")
303                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
304                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
305                .setGroupId("testGroup")
306                .build());
307        defaultAccount = mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
308                PhoneAccount.SCHEME_TEL);
309        assertEquals(telAccount2, defaultAccount);
310        assertNull(mRegistrar.getPhoneAccountUnchecked(telAccount1));
311    }
312
313    @MediumTest
314    public void testAddSameDefault() throws Exception {
315        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
316                Mockito.mock(IConnectionService.class));
317
318        // By default, there is no default outgoing account (nothing has been registered)
319        assertNull(
320                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL));
321
322        // Register one tel: account
323        PhoneAccountHandle telAccount1 = makeQuickAccountHandle("tel_acct1");
324        registerAndEnableAccount(new PhoneAccount.Builder(telAccount1, "tel_acct1")
325                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
326                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
327                .setGroupId("testGroup")
328                .build());
329        mRegistrar.setUserSelectedOutgoingPhoneAccount(telAccount1, Process.myUserHandle());
330        PhoneAccountHandle defaultAccount =
331                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
332        assertEquals(telAccount1, defaultAccount);
333        mRegistrar.unregisterPhoneAccount(telAccount1);
334
335        // Register Emergency Account and unregister
336        PhoneAccountHandle emerAccount = makeQuickAccountHandle("emer_acct");
337        registerAndEnableAccount(new PhoneAccount.Builder(emerAccount, "emer_acct")
338                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
339                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
340                .build());
341        defaultAccount =
342                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
343        assertNull(defaultAccount);
344        mRegistrar.unregisterPhoneAccount(emerAccount);
345
346        // Re-register the same account and make sure the default is in place
347        registerAndEnableAccount(new PhoneAccount.Builder(telAccount1, "tel_acct1")
348                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
349                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
350                .setGroupId("testGroup")
351                .build());
352        defaultAccount =
353                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
354        assertEquals(telAccount1, defaultAccount);
355    }
356
357    @MediumTest
358    public void testAddSameGroup() throws Exception {
359        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
360                Mockito.mock(IConnectionService.class));
361
362        // By default, there is no default outgoing account (nothing has been registered)
363        assertNull(
364                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL));
365
366        // Register one tel: account
367        PhoneAccountHandle telAccount1 = makeQuickAccountHandle("tel_acct1");
368        registerAndEnableAccount(new PhoneAccount.Builder(telAccount1, "tel_acct1")
369                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
370                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
371                .setGroupId("testGroup")
372                .build());
373        mRegistrar.setUserSelectedOutgoingPhoneAccount(telAccount1, Process.myUserHandle());
374        PhoneAccountHandle defaultAccount =
375                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
376        assertEquals(telAccount1, defaultAccount);
377        mRegistrar.unregisterPhoneAccount(telAccount1);
378
379        // Register Emergency Account and unregister
380        PhoneAccountHandle emerAccount = makeQuickAccountHandle("emer_acct");
381        registerAndEnableAccount(new PhoneAccount.Builder(emerAccount, "emer_acct")
382                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
383                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
384                .build());
385        defaultAccount =
386                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
387        assertNull(defaultAccount);
388        mRegistrar.unregisterPhoneAccount(emerAccount);
389
390        // Re-register a new account with the same group
391        PhoneAccountHandle telAccount2 = makeQuickAccountHandle("tel_acct2");
392        registerAndEnableAccount(new PhoneAccount.Builder(telAccount2, "tel_acct2")
393                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
394                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
395                .setGroupId("testGroup")
396                .build());
397        defaultAccount =
398                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
399        assertEquals(telAccount2, defaultAccount);
400    }
401
402    @MediumTest
403    public void testAddSameGroupButDifferentComponent() throws Exception {
404        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
405                Mockito.mock(IConnectionService.class));
406
407        // By default, there is no default outgoing account (nothing has been registered)
408        assertNull(mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
409                PhoneAccount.SCHEME_TEL));
410
411        // Register one tel: account
412        PhoneAccountHandle telAccount1 = makeQuickAccountHandle("tel_acct1");
413        registerAndEnableAccount(new PhoneAccount.Builder(telAccount1, "tel_acct1")
414                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
415                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
416                .setGroupId("testGroup")
417                .build());
418        mRegistrar.setUserSelectedOutgoingPhoneAccount(telAccount1, Process.myUserHandle());
419        PhoneAccountHandle defaultAccount =
420                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
421        assertEquals(telAccount1, defaultAccount);
422        assertNotNull(mRegistrar.getPhoneAccountUnchecked(telAccount1));
423
424        // Register a new account with the same group, but different Component, so don't replace
425        // Default
426        PhoneAccountHandle telAccount2 =  makeQuickAccountHandle(
427                new ComponentName("other1", "other2"), "tel_acct2");
428        registerAndEnableAccount(new PhoneAccount.Builder(telAccount2, "tel_acct2")
429                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
430                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
431                .setGroupId("testGroup")
432                .build());
433        assertNotNull(mRegistrar.getPhoneAccountUnchecked(telAccount2));
434
435        defaultAccount =
436                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
437        assertEquals(telAccount1, defaultAccount);
438    }
439
440    @MediumTest
441    public void testAddSameGroupButDifferentComponent2() throws Exception {
442        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
443                Mockito.mock(IConnectionService.class));
444
445        // By default, there is no default outgoing account (nothing has been registered)
446        assertNull(mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
447                PhoneAccount.SCHEME_TEL));
448
449        // Register first tel: account
450        PhoneAccountHandle telAccount1 =  makeQuickAccountHandle(
451                new ComponentName("other1", "other2"), "tel_acct1");
452        registerAndEnableAccount(new PhoneAccount.Builder(telAccount1, "tel_acct1")
453                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
454                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
455                .setGroupId("testGroup")
456                .build());
457        assertNotNull(mRegistrar.getPhoneAccountUnchecked(telAccount1));
458        mRegistrar.setUserSelectedOutgoingPhoneAccount(telAccount1, Process.myUserHandle());
459
460        // Register second account with the same group, but a second Component, so don't replace
461        // Default
462        PhoneAccountHandle telAccount2 = makeQuickAccountHandle("tel_acct2");
463        registerAndEnableAccount(new PhoneAccount.Builder(telAccount2, "tel_acct2")
464                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
465                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
466                .setGroupId("testGroup")
467                .build());
468
469        PhoneAccountHandle defaultAccount =
470                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL);
471        assertEquals(telAccount1, defaultAccount);
472
473        // Register third account with the second component name, but same group id
474        PhoneAccountHandle telAccount3 = makeQuickAccountHandle("tel_acct3");
475        registerAndEnableAccount(new PhoneAccount.Builder(telAccount3, "tel_acct3")
476                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
477                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
478                .setGroupId("testGroup")
479                .build());
480
481        // Make sure that the default account is still the original PhoneAccount and that the
482        // second PhoneAccount with the second ComponentName was replaced by the third PhoneAccount
483        defaultAccount =
484                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL);
485        assertEquals(telAccount1, defaultAccount);
486
487        assertNotNull(mRegistrar.getPhoneAccountUnchecked(telAccount1));
488        assertNull(mRegistrar.getPhoneAccountUnchecked(telAccount2));
489        assertNotNull(mRegistrar.getPhoneAccountUnchecked(telAccount3));
490    }
491
492    @MediumTest
493    public void testPhoneAccountParceling() throws Exception {
494        PhoneAccountHandle handle = makeQuickAccountHandle("foo");
495        roundTripPhoneAccount(new PhoneAccount.Builder(handle, null).build());
496        roundTripPhoneAccount(new PhoneAccount.Builder(handle, "foo").build());
497        roundTripPhoneAccount(
498                new PhoneAccount.Builder(handle, "foo")
499                        .setAddress(Uri.parse("tel:123456"))
500                        .setCapabilities(23)
501                        .setHighlightColor(0xf0f0f0)
502                        .setIcon(Icon.createWithResource(
503                                "com.android.server.telecom.tests", R.drawable.stat_sys_phone_call))
504                        // TODO: set icon tint (0xfefefe)
505                        .setShortDescription("short description")
506                        .setSubscriptionAddress(Uri.parse("tel:2345678"))
507                        .setSupportedUriSchemes(Arrays.asList("tel", "sip"))
508                        .setGroupId("testGroup")
509                        .build());
510        roundTripPhoneAccount(
511                new PhoneAccount.Builder(handle, "foo")
512                        .setAddress(Uri.parse("tel:123456"))
513                        .setCapabilities(23)
514                        .setHighlightColor(0xf0f0f0)
515                        .setIcon(Icon.createWithBitmap(
516                                BitmapFactory.decodeResource(
517                                        getContext().getResources(),
518                                        R.drawable.stat_sys_phone_call)))
519                        .setShortDescription("short description")
520                        .setSubscriptionAddress(Uri.parse("tel:2345678"))
521                        .setSupportedUriSchemes(Arrays.asList("tel", "sip"))
522                        .setGroupId("testGroup")
523                        .build());
524    }
525
526    private static ComponentName makeQuickConnectionServiceComponentName() {
527        return new ComponentName(
528                "com.android.server.telecom.tests",
529                "com.android.server.telecom.tests.MockConnectionService");
530    }
531
532    private static PhoneAccountHandle makeQuickAccountHandle(String id) {
533        return makeQuickAccountHandle(makeQuickConnectionServiceComponentName(), id);
534    }
535
536    private static PhoneAccountHandle makeQuickAccountHandle(ComponentName name, String id) {
537        return new PhoneAccountHandle(name, id, Process.myUserHandle());
538    }
539
540    private PhoneAccount.Builder makeQuickAccountBuilder(String id, int idx) {
541        return new PhoneAccount.Builder(
542                makeQuickAccountHandle(id),
543                "label" + idx);
544    }
545
546    private PhoneAccount makeQuickAccount(String id, int idx) {
547        return makeQuickAccountBuilder(id, idx)
548                .setAddress(Uri.parse("http://foo.com/" + idx))
549                .setSubscriptionAddress(Uri.parse("tel:555-000" + idx))
550                .setCapabilities(idx)
551                .setIcon(Icon.createWithResource(
552                            "com.android.server.telecom.tests", R.drawable.stat_sys_phone_call))
553                .setShortDescription("desc" + idx)
554                .setIsEnabled(true)
555                .build();
556    }
557
558    private static void roundTripPhoneAccount(PhoneAccount original) throws Exception {
559        PhoneAccount copy = null;
560
561        {
562            Parcel parcel = Parcel.obtain();
563            parcel.writeParcelable(original, 0);
564            parcel.setDataPosition(0);
565            copy = parcel.readParcelable(PhoneAccountRegistrarTest.class.getClassLoader());
566            parcel.recycle();
567        }
568
569        assertPhoneAccountEquals(original, copy);
570    }
571
572    private static <T> T roundTripXml(
573            Object self,
574            T input,
575            PhoneAccountRegistrar.XmlSerialization<T> xml,
576            Context context)
577            throws Exception {
578        Log.d(self, "Input = %s", input);
579
580        byte[] data;
581        {
582            XmlSerializer serializer = new FastXmlSerializer();
583            ByteArrayOutputStream baos = new ByteArrayOutputStream();
584            serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
585            xml.writeToXml(input, serializer, context);
586            serializer.flush();
587            data = baos.toByteArray();
588        }
589
590        Log.i(self, "====== XML data ======\n%s", new String(data));
591
592        T result = null;
593        {
594            XmlPullParser parser = Xml.newPullParser();
595            parser.setInput(new BufferedInputStream(new ByteArrayInputStream(data)), null);
596            parser.nextTag();
597            result = xml.readFromXml(parser, MAX_VERSION, context);
598        }
599
600        Log.i(self, "result = " + result);
601
602        return result;
603    }
604
605    private static void assertPhoneAccountHandleEquals(PhoneAccountHandle a, PhoneAccountHandle b) {
606        if (a != b) {
607            assertEquals(
608                    a.getComponentName().getPackageName(),
609                    b.getComponentName().getPackageName());
610            assertEquals(
611                    a.getComponentName().getClassName(),
612                    b.getComponentName().getClassName());
613            assertEquals(a.getId(), b.getId());
614        }
615    }
616
617    private static void assertIconEquals(Icon a, Icon b) {
618        if (a != b) {
619            if (a != null && b != null) {
620                assertEquals(a.toString(), b.toString());
621            } else {
622                fail("Icons not equal: " + a + ", " + b);
623            }
624        }
625    }
626
627    private static void assertDefaultPhoneAccountHandleEquals(DefaultPhoneAccountHandle a,
628            DefaultPhoneAccountHandle b) {
629        if (a != b) {
630            if (a!= null && b != null) {
631                assertEquals(a.userHandle, b.userHandle);
632                assertPhoneAccountHandleEquals(a.phoneAccountHandle, b.phoneAccountHandle);
633            } else {
634                fail("Default phone account handles are not equal: " + a + ", " + b);
635            }
636        }
637    }
638
639    private static void assertPhoneAccountEquals(PhoneAccount a, PhoneAccount b) {
640        if (a != b) {
641            if (a != null && b != null) {
642                assertPhoneAccountHandleEquals(a.getAccountHandle(), b.getAccountHandle());
643                assertEquals(a.getAddress(), b.getAddress());
644                assertEquals(a.getSubscriptionAddress(), b.getSubscriptionAddress());
645                assertEquals(a.getCapabilities(), b.getCapabilities());
646                assertIconEquals(a.getIcon(), b.getIcon());
647                assertEquals(a.getHighlightColor(), b.getHighlightColor());
648                assertEquals(a.getLabel(), b.getLabel());
649                assertEquals(a.getShortDescription(), b.getShortDescription());
650                assertEquals(a.getSupportedUriSchemes(), b.getSupportedUriSchemes());
651                assertBundlesEqual(a.getExtras(), b.getExtras());
652                assertEquals(a.isEnabled(), b.isEnabled());
653            } else {
654                fail("Phone accounts not equal: " + a + ", " + b);
655            }
656        }
657    }
658
659    private static void assertBundlesEqual(Bundle a, Bundle b) {
660        if (a == null && b == null) {
661            return;
662        }
663
664        assertNotNull(a);
665        assertNotNull(b);
666        Set<String> keySetA = a.keySet();
667        Set<String> keySetB = b.keySet();
668
669        assertTrue("Bundle keys not the same", keySetA.containsAll(keySetB));
670        assertTrue("Bundle keys not the same", keySetB.containsAll(keySetA));
671
672        for (String keyA : keySetA) {
673            assertEquals("Bundle value not the same", a.get(keyA), b.get(keyA));
674        }
675    }
676
677    private static void assertStateEquals(
678            PhoneAccountRegistrar.State a, PhoneAccountRegistrar.State b) {
679        assertEquals(a.defaultOutgoingAccountHandles.size(),
680                b.defaultOutgoingAccountHandles.size());
681        for (int i = 0; i < a.defaultOutgoingAccountHandles.size(); i++) {
682            assertDefaultPhoneAccountHandleEquals(a.defaultOutgoingAccountHandles.get(i),
683                    b.defaultOutgoingAccountHandles.get(i));
684        }
685        assertEquals(a.accounts.size(), b.accounts.size());
686        for (int i = 0; i < a.accounts.size(); i++) {
687            assertPhoneAccountEquals(a.accounts.get(i), b.accounts.get(i));
688        }
689    }
690
691    private PhoneAccountRegistrar.State makeQuickState() {
692        PhoneAccountRegistrar.State s = new PhoneAccountRegistrar.State();
693        s.accounts.add(makeQuickAccount("id0", 0));
694        s.accounts.add(makeQuickAccount("id1", 1));
695        s.accounts.add(makeQuickAccount("id2", 2));
696        PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle(
697                new ComponentName("pkg0", "cls0"), "id0");
698        UserHandle userHandle = phoneAccountHandle.getUserHandle();
699        s.defaultOutgoingAccountHandles
700                .put(userHandle, new DefaultPhoneAccountHandle(userHandle, phoneAccountHandle,
701                        "testGroup"));
702        return s;
703    }
704}
705