PhoneAccountRegistrarTest.java revision a3799ae6aafba8ccd6448a7c4337acd3460b49f2
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.PhoneAccount; 30import android.telecom.PhoneAccountHandle; 31import android.telecom.TelecomManager; 32import android.test.suitebuilder.annotation.MediumTest; 33import android.util.Xml; 34 35import com.android.internal.telecom.IConnectionService; 36import com.android.internal.util.FastXmlSerializer; 37import com.android.server.telecom.Log; 38import com.android.server.telecom.PhoneAccountRegistrar; 39import com.android.server.telecom.PhoneAccountRegistrar.DefaultPhoneAccountHandle; 40 41import org.mockito.Mock; 42import org.mockito.Mockito; 43import org.mockito.MockitoAnnotations; 44import org.xmlpull.v1.XmlPullParser; 45import org.xmlpull.v1.XmlSerializer; 46 47import java.io.BufferedInputStream; 48import java.io.BufferedOutputStream; 49import java.io.ByteArrayInputStream; 50import java.io.ByteArrayOutputStream; 51import java.io.File; 52import java.util.Arrays; 53import java.util.Set; 54 55public class PhoneAccountRegistrarTest extends TelecomTestCase { 56 57 private static final int MAX_VERSION = Integer.MAX_VALUE; 58 private static final String FILE_NAME = "phone-account-registrar-test-1223.xml"; 59 private PhoneAccountRegistrar mRegistrar; 60 @Mock 61 private TelecomManager mTelecomManager; 62 63 @Override 64 public void setUp() throws Exception { 65 super.setUp(); 66 MockitoAnnotations.initMocks(this); 67 mComponentContextFixture.setTelecomManager(mTelecomManager); 68 new File( 69 mComponentContextFixture.getTestDouble().getApplicationContext().getFilesDir(), 70 FILE_NAME) 71 .delete(); 72 mRegistrar = new PhoneAccountRegistrar( 73 mComponentContextFixture.getTestDouble().getApplicationContext(), 74 FILE_NAME); 75 } 76 77 @Override 78 public void tearDown() throws Exception { 79 mRegistrar = null; 80 new File( 81 mComponentContextFixture.getTestDouble().getApplicationContext().getFilesDir(), 82 FILE_NAME) 83 .delete(); 84 super.tearDown(); 85 } 86 87 @MediumTest 88 public void testPhoneAccountHandle() throws Exception { 89 PhoneAccountHandle input = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id0"); 90 PhoneAccountHandle result = roundTripXml(this, input, 91 PhoneAccountRegistrar.sPhoneAccountHandleXml, mContext); 92 assertPhoneAccountHandleEquals(input, result); 93 94 PhoneAccountHandle inputN = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), null); 95 PhoneAccountHandle resultN = roundTripXml(this, inputN, 96 PhoneAccountRegistrar.sPhoneAccountHandleXml, mContext); 97 Log.i(this, "inputN = %s, resultN = %s", inputN, resultN); 98 assertPhoneAccountHandleEquals(inputN, resultN); 99 } 100 101 @MediumTest 102 public void testPhoneAccount() throws Exception { 103 Bundle testBundle = new Bundle(); 104 testBundle.putInt("EXTRA_INT_1", 1); 105 testBundle.putInt("EXTRA_INT_100", 100); 106 testBundle.putBoolean("EXTRA_BOOL_TRUE", true); 107 testBundle.putBoolean("EXTRA_BOOL_FALSE", false); 108 testBundle.putString("EXTRA_STR1", "Hello"); 109 testBundle.putString("EXTRA_STR2", "There"); 110 111 PhoneAccount input = makeQuickAccountBuilder("id0", 0) 112 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL) 113 .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL) 114 .setExtras(testBundle) 115 .setIsEnabled(true) 116 .build(); 117 PhoneAccount result = roundTripXml(this, input, PhoneAccountRegistrar.sPhoneAccountXml, 118 mContext); 119 120 assertPhoneAccountEquals(input, result); 121 } 122 123 /** 124 * Test to ensure non-supported values 125 * @throws Exception 126 */ 127 @MediumTest 128 public void testPhoneAccountExtrasEdge() throws Exception { 129 Bundle testBundle = new Bundle(); 130 // Ensure null values for string are not persisted. 131 testBundle.putString("EXTRA_STR2", null); 132 // 133 134 // Ensure unsupported data types are not persisted. 135 testBundle.putShort("EXTRA_SHORT", (short) 2); 136 testBundle.putByte("EXTRA_BYTE", (byte) 1); 137 testBundle.putParcelable("EXTRA_PARC", new Rect(1, 1, 1, 1)); 138 // Put in something valid so the bundle exists. 139 testBundle.putString("EXTRA_OK", "OK"); 140 141 PhoneAccount input = makeQuickAccountBuilder("id0", 0) 142 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL) 143 .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL) 144 .setExtras(testBundle) 145 .build(); 146 PhoneAccount result = roundTripXml(this, input, PhoneAccountRegistrar.sPhoneAccountXml, 147 mContext); 148 149 Bundle extras = result.getExtras(); 150 assertFalse(extras.keySet().contains("EXTRA_STR2")); 151 assertFalse(extras.keySet().contains("EXTRA_SHORT")); 152 assertFalse(extras.keySet().contains("EXTRA_BYTE")); 153 assertFalse(extras.keySet().contains("EXTRA_PARC")); 154 } 155 156 @MediumTest 157 public void testState() throws Exception { 158 PhoneAccountRegistrar.State input = makeQuickState(); 159 PhoneAccountRegistrar.State result = roundTripXml(this, input, 160 PhoneAccountRegistrar.sStateXml, 161 mContext); 162 assertStateEquals(input, result); 163 } 164 165 private void registerAndEnableAccount(PhoneAccount account) { 166 mRegistrar.registerPhoneAccount(account); 167 mRegistrar.enablePhoneAccount(account.getAccountHandle(), true); 168 } 169 170 @MediumTest 171 public void testAccounts() throws Exception { 172 int i = 0; 173 174 mComponentContextFixture.addConnectionService( 175 makeQuickConnectionServiceComponentName(), 176 Mockito.mock(IConnectionService.class)); 177 178 registerAndEnableAccount(makeQuickAccountBuilder("id" + i, i++) 179 .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER 180 | PhoneAccount.CAPABILITY_CALL_PROVIDER) 181 .build()); 182 registerAndEnableAccount(makeQuickAccountBuilder("id" + i, i++) 183 .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER 184 | PhoneAccount.CAPABILITY_CALL_PROVIDER) 185 .build()); 186 registerAndEnableAccount(makeQuickAccountBuilder("id" + i, i++) 187 .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER 188 | PhoneAccount.CAPABILITY_CALL_PROVIDER) 189 .build()); 190 registerAndEnableAccount(makeQuickAccountBuilder("id" + i, i++) 191 .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER) 192 .build()); 193 194 assertEquals(4, mRegistrar.getAllPhoneAccountsOfCurrentUser().size()); 195 assertEquals(3, mRegistrar.getCallCapablePhoneAccountsOfCurrentUser(null, false).size()); 196 assertEquals(null, mRegistrar.getSimCallManagerOfCurrentUser()); 197 assertEquals(null, mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser( 198 PhoneAccount.SCHEME_TEL)); 199 } 200 201 @MediumTest 202 public void testSimCallManager() throws Exception { 203 // TODO 204 } 205 206 @MediumTest 207 public void testDefaultOutgoing() throws Exception { 208 mComponentContextFixture.addConnectionService( 209 makeQuickConnectionServiceComponentName(), 210 Mockito.mock(IConnectionService.class)); 211 212 // By default, there is no default outgoing account (nothing has been registered) 213 assertNull( 214 mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL)); 215 216 // Register one tel: account 217 PhoneAccountHandle telAccount = makeQuickAccountHandle("tel_acct"); 218 registerAndEnableAccount(new PhoneAccount.Builder(telAccount, "tel_acct") 219 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) 220 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL) 221 .build()); 222 PhoneAccountHandle defaultAccount = 223 mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL); 224 assertEquals(telAccount, defaultAccount); 225 226 // Add a SIP account, make sure tel: doesn't change 227 PhoneAccountHandle sipAccount = makeQuickAccountHandle("sip_acct"); 228 registerAndEnableAccount(new PhoneAccount.Builder(sipAccount, "sip_acct") 229 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) 230 .addSupportedUriScheme(PhoneAccount.SCHEME_SIP) 231 .build()); 232 defaultAccount = mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser( 233 PhoneAccount.SCHEME_SIP); 234 assertEquals(sipAccount, defaultAccount); 235 defaultAccount = mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser( 236 PhoneAccount.SCHEME_TEL); 237 assertEquals(telAccount, defaultAccount); 238 239 // Add a connection manager, make sure tel: doesn't change 240 PhoneAccountHandle connectionManager = makeQuickAccountHandle("mgr_acct"); 241 registerAndEnableAccount(new PhoneAccount.Builder(connectionManager, "mgr_acct") 242 .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER) 243 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL) 244 .build()); 245 defaultAccount = mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser( 246 PhoneAccount.SCHEME_TEL); 247 assertEquals(telAccount, defaultAccount); 248 249 // Unregister the tel: account, make sure there is no tel: default now. 250 mRegistrar.unregisterPhoneAccount(telAccount); 251 assertNull( 252 mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL)); 253 } 254 255 @MediumTest 256 public void testPhoneAccountParceling() throws Exception { 257 PhoneAccountHandle handle = makeQuickAccountHandle("foo"); 258 roundTripPhoneAccount(new PhoneAccount.Builder(handle, null).build()); 259 roundTripPhoneAccount(new PhoneAccount.Builder(handle, "foo").build()); 260 roundTripPhoneAccount( 261 new PhoneAccount.Builder(handle, "foo") 262 .setAddress(Uri.parse("tel:123456")) 263 .setCapabilities(23) 264 .setHighlightColor(0xf0f0f0) 265 .setIcon(Icon.createWithResource( 266 "com.android.server.telecom.tests", R.drawable.stat_sys_phone_call)) 267 // TODO: set icon tint (0xfefefe) 268 .setShortDescription("short description") 269 .setSubscriptionAddress(Uri.parse("tel:2345678")) 270 .setSupportedUriSchemes(Arrays.asList("tel", "sip")) 271 .build()); 272 roundTripPhoneAccount( 273 new PhoneAccount.Builder(handle, "foo") 274 .setAddress(Uri.parse("tel:123456")) 275 .setCapabilities(23) 276 .setHighlightColor(0xf0f0f0) 277 .setIcon(Icon.createWithBitmap( 278 BitmapFactory.decodeResource( 279 getContext().getResources(), 280 R.drawable.stat_sys_phone_call))) 281 .setShortDescription("short description") 282 .setSubscriptionAddress(Uri.parse("tel:2345678")) 283 .setSupportedUriSchemes(Arrays.asList("tel", "sip")) 284 .build()); 285 } 286 287 private static ComponentName makeQuickConnectionServiceComponentName() { 288 return new ComponentName( 289 "com.android.server.telecom.tests", 290 "com.android.server.telecom.tests.MockConnectionService"); 291 } 292 293 private static PhoneAccountHandle makeQuickAccountHandle(String id) { 294 return new PhoneAccountHandle( 295 makeQuickConnectionServiceComponentName(), 296 id, 297 Process.myUserHandle()); 298 } 299 300 private PhoneAccount.Builder makeQuickAccountBuilder(String id, int idx) { 301 return new PhoneAccount.Builder( 302 makeQuickAccountHandle(id), 303 "label" + idx); 304 } 305 306 private PhoneAccount makeQuickAccount(String id, int idx) { 307 return makeQuickAccountBuilder(id, idx) 308 .setAddress(Uri.parse("http://foo.com/" + idx)) 309 .setSubscriptionAddress(Uri.parse("tel:555-000" + idx)) 310 .setCapabilities(idx) 311 .setIcon(Icon.createWithResource( 312 "com.android.server.telecom.tests", R.drawable.stat_sys_phone_call)) 313 .setShortDescription("desc" + idx) 314 .setIsEnabled(true) 315 .build(); 316 } 317 318 private static void roundTripPhoneAccount(PhoneAccount original) throws Exception { 319 PhoneAccount copy = null; 320 321 { 322 Parcel parcel = Parcel.obtain(); 323 parcel.writeParcelable(original, 0); 324 parcel.setDataPosition(0); 325 copy = parcel.readParcelable(PhoneAccountRegistrarTest.class.getClassLoader()); 326 parcel.recycle(); 327 } 328 329 assertPhoneAccountEquals(original, copy); 330 } 331 332 private static <T> T roundTripXml( 333 Object self, 334 T input, 335 PhoneAccountRegistrar.XmlSerialization<T> xml, 336 Context context) 337 throws Exception { 338 Log.d(self, "Input = %s", input); 339 340 byte[] data; 341 { 342 XmlSerializer serializer = new FastXmlSerializer(); 343 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 344 serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); 345 xml.writeToXml(input, serializer, context); 346 serializer.flush(); 347 data = baos.toByteArray(); 348 } 349 350 Log.i(self, "====== XML data ======\n%s", new String(data)); 351 352 T result = null; 353 { 354 XmlPullParser parser = Xml.newPullParser(); 355 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(data)), null); 356 parser.nextTag(); 357 result = xml.readFromXml(parser, MAX_VERSION, context); 358 } 359 360 Log.i(self, "result = " + result); 361 362 return result; 363 } 364 365 private static void assertPhoneAccountHandleEquals(PhoneAccountHandle a, PhoneAccountHandle b) { 366 if (a != b) { 367 assertEquals( 368 a.getComponentName().getPackageName(), 369 b.getComponentName().getPackageName()); 370 assertEquals( 371 a.getComponentName().getClassName(), 372 b.getComponentName().getClassName()); 373 assertEquals(a.getId(), b.getId()); 374 } 375 } 376 377 private static void assertIconEquals(Icon a, Icon b) { 378 if (a != b) { 379 if (a != null && b != null) { 380 assertEquals(a.toString(), b.toString()); 381 } else { 382 fail("Icons not equal: " + a + ", " + b); 383 } 384 } 385 } 386 387 private static void assertDefaultPhoneAccountHandleEquals(DefaultPhoneAccountHandle a, 388 DefaultPhoneAccountHandle b) { 389 if (a != b) { 390 if (a!= null && b != null) { 391 assertEquals(a.userHandle, b.userHandle); 392 assertPhoneAccountHandleEquals(a.phoneAccountHandle, b.phoneAccountHandle); 393 } else { 394 fail("Default phone account handles are not equal: " + a + ", " + b); 395 } 396 } 397 } 398 399 private static void assertPhoneAccountEquals(PhoneAccount a, PhoneAccount b) { 400 if (a != b) { 401 if (a != null && b != null) { 402 assertPhoneAccountHandleEquals(a.getAccountHandle(), b.getAccountHandle()); 403 assertEquals(a.getAddress(), b.getAddress()); 404 assertEquals(a.getSubscriptionAddress(), b.getSubscriptionAddress()); 405 assertEquals(a.getCapabilities(), b.getCapabilities()); 406 assertIconEquals(a.getIcon(), b.getIcon()); 407 assertEquals(a.getHighlightColor(), b.getHighlightColor()); 408 assertEquals(a.getLabel(), b.getLabel()); 409 assertEquals(a.getShortDescription(), b.getShortDescription()); 410 assertEquals(a.getSupportedUriSchemes(), b.getSupportedUriSchemes()); 411 assertBundlesEqual(a.getExtras(), b.getExtras()); 412 assertEquals(a.isEnabled(), b.isEnabled()); 413 } else { 414 fail("Phone accounts not equal: " + a + ", " + b); 415 } 416 } 417 } 418 419 private static void assertBundlesEqual(Bundle a, Bundle b) { 420 if (a == null && b == null) { 421 return; 422 } 423 424 assertNotNull(a); 425 assertNotNull(b); 426 Set<String> keySetA = a.keySet(); 427 Set<String> keySetB = b.keySet(); 428 429 assertTrue("Bundle keys not the same", keySetA.containsAll(keySetB)); 430 assertTrue("Bundle keys not the same", keySetB.containsAll(keySetA)); 431 432 for (String keyA : keySetA) { 433 assertEquals("Bundle value not the same", a.get(keyA), b.get(keyA)); 434 } 435 } 436 437 private static void assertStateEquals( 438 PhoneAccountRegistrar.State a, PhoneAccountRegistrar.State b) { 439 assertEquals(a.defaultOutgoingAccountHandles.size(), 440 b.defaultOutgoingAccountHandles.size()); 441 for (int i = 0; i < a.defaultOutgoingAccountHandles.size(); i++) { 442 assertDefaultPhoneAccountHandleEquals(a.defaultOutgoingAccountHandles.get(i), 443 b.defaultOutgoingAccountHandles.get(i)); 444 } 445 assertEquals(a.accounts.size(), b.accounts.size()); 446 for (int i = 0; i < a.accounts.size(); i++) { 447 assertPhoneAccountEquals(a.accounts.get(i), b.accounts.get(i)); 448 } 449 } 450 451 private PhoneAccountRegistrar.State makeQuickState() { 452 PhoneAccountRegistrar.State s = new PhoneAccountRegistrar.State(); 453 s.accounts.add(makeQuickAccount("id0", 0)); 454 s.accounts.add(makeQuickAccount("id1", 1)); 455 s.accounts.add(makeQuickAccount("id2", 2)); 456 PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle( 457 new ComponentName("pkg0", "cls0"), "id0"); 458 UserHandle userHandle = phoneAccountHandle.getUserHandle(); 459 s.defaultOutgoingAccountHandles 460 .put(userHandle, new DefaultPhoneAccountHandle(userHandle, phoneAccountHandle)); 461 return s; 462 } 463} 464