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