1 /* 2 * Copyright (C) 2018 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 17 package android.provider; 18 19 import static android.provider.DeviceConfig.Properties; 20 21 import static com.google.common.truth.Truth.assertThat; 22 23 import static org.testng.Assert.assertThrows; 24 25 import android.app.ActivityThread; 26 import android.content.ContentResolver; 27 import android.os.Bundle; 28 import android.platform.test.annotations.Presubmit; 29 30 import androidx.test.InstrumentationRegistry; 31 import androidx.test.filters.SmallTest; 32 import androidx.test.runner.AndroidJUnit4; 33 34 import org.junit.After; 35 import org.junit.Assert; 36 import org.junit.Test; 37 import org.junit.runner.RunWith; 38 39 import java.util.HashMap; 40 import java.util.Map; 41 import java.util.Objects; 42 import java.util.concurrent.CompletableFuture; 43 import java.util.concurrent.ExecutionException; 44 import java.util.concurrent.TimeUnit; 45 import java.util.concurrent.TimeoutException; 46 import java.util.concurrent.atomic.AtomicReference; 47 48 /** Tests that ensure appropriate settings are backed up. */ 49 @Presubmit 50 @RunWith(AndroidJUnit4.class) 51 @SmallTest 52 public class DeviceConfigTest { 53 private static final long WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS = 2000; // 2 sec 54 private static final String DEFAULT_VALUE = "test_default_value"; 55 private static final String NAMESPACE = "namespace1"; 56 private static final String KEY = "key1"; 57 private static final String KEY2 = "key2"; 58 private static final String KEY3 = "key3"; 59 private static final String KEY4 = "key4"; 60 private static final String VALUE = "value1"; 61 private static final String VALUE2 = "value2"; 62 private static final String VALUE3 = "value3"; 63 private static final String NULL_VALUE = "null"; 64 65 @After cleanUp()66 public void cleanUp() { 67 deleteViaContentProvider(NAMESPACE, KEY); 68 deleteViaContentProvider(NAMESPACE, KEY2); 69 deleteViaContentProvider(NAMESPACE, KEY3); 70 } 71 72 @Test getProperty_empty()73 public void getProperty_empty() { 74 String result = DeviceConfig.getProperty(NAMESPACE, KEY); 75 assertThat(result).isNull(); 76 } 77 78 @Test getProperty_nullNamespace()79 public void getProperty_nullNamespace() { 80 try { 81 DeviceConfig.getProperty(null, KEY); 82 Assert.fail("Null namespace should have resulted in an NPE."); 83 } catch (NullPointerException e) { 84 // expected 85 } 86 } 87 88 @Test getProperty_nullName()89 public void getProperty_nullName() { 90 try { 91 DeviceConfig.getProperty(NAMESPACE, null); 92 Assert.fail("Null name should have resulted in an NPE."); 93 } catch (NullPointerException e) { 94 // expected 95 } 96 } 97 98 @Test getString_empty()99 public void getString_empty() { 100 final String default_value = "default_value"; 101 final String result = DeviceConfig.getString(NAMESPACE, KEY, default_value); 102 assertThat(result).isEqualTo(default_value); 103 } 104 105 @Test getString_nullDefault()106 public void getString_nullDefault() { 107 final String result = DeviceConfig.getString(NAMESPACE, KEY, null); 108 assertThat(result).isNull(); 109 } 110 111 @Test getString_nonEmpty()112 public void getString_nonEmpty() { 113 final String value = "new_value"; 114 final String default_value = "default"; 115 DeviceConfig.setProperty(NAMESPACE, KEY, value, false); 116 117 final String result = DeviceConfig.getString(NAMESPACE, KEY, default_value); 118 assertThat(result).isEqualTo(value); 119 } 120 121 @Test getString_nullNamespace()122 public void getString_nullNamespace() { 123 try { 124 DeviceConfig.getString(null, KEY, "default_value"); 125 Assert.fail("Null namespace should have resulted in an NPE."); 126 } catch (NullPointerException e) { 127 // expected 128 } 129 } 130 131 @Test getString_nullName()132 public void getString_nullName() { 133 try { 134 DeviceConfig.getString(NAMESPACE, null, "default_value"); 135 Assert.fail("Null name should have resulted in an NPE."); 136 } catch (NullPointerException e) { 137 // expected 138 } 139 } 140 141 @Test getBoolean_empty()142 public void getBoolean_empty() { 143 final boolean default_value = true; 144 final boolean result = DeviceConfig.getBoolean(NAMESPACE, KEY, default_value); 145 assertThat(result).isEqualTo(default_value); 146 } 147 148 @Test getBoolean_valid()149 public void getBoolean_valid() { 150 final boolean value = true; 151 final boolean default_value = false; 152 DeviceConfig.setProperty(NAMESPACE, KEY, String.valueOf(value), false); 153 154 final boolean result = DeviceConfig.getBoolean(NAMESPACE, KEY, default_value); 155 assertThat(result).isEqualTo(value); 156 } 157 158 @Test getBoolean_invalid()159 public void getBoolean_invalid() { 160 final boolean default_value = true; 161 DeviceConfig.setProperty(NAMESPACE, KEY, "not_a_boolean", false); 162 163 final boolean result = DeviceConfig.getBoolean(NAMESPACE, KEY, default_value); 164 // Anything non-null other than case insensitive "true" parses to false. 165 assertThat(result).isFalse(); 166 } 167 168 @Test getBoolean_nullNamespace()169 public void getBoolean_nullNamespace() { 170 try { 171 DeviceConfig.getBoolean(null, KEY, false); 172 Assert.fail("Null namespace should have resulted in an NPE."); 173 } catch (NullPointerException e) { 174 // expected 175 } 176 } 177 178 @Test getBoolean_nullName()179 public void getBoolean_nullName() { 180 try { 181 DeviceConfig.getBoolean(NAMESPACE, null, false); 182 Assert.fail("Null name should have resulted in an NPE."); 183 } catch (NullPointerException e) { 184 // expected 185 } 186 } 187 188 @Test getInt_empty()189 public void getInt_empty() { 190 final int default_value = 999; 191 final int result = DeviceConfig.getInt(NAMESPACE, KEY, default_value); 192 assertThat(result).isEqualTo(default_value); 193 } 194 195 @Test getInt_valid()196 public void getInt_valid() { 197 final int value = 123; 198 final int default_value = 999; 199 DeviceConfig.setProperty(NAMESPACE, KEY, String.valueOf(value), false); 200 201 final int result = DeviceConfig.getInt(NAMESPACE, KEY, default_value); 202 assertThat(result).isEqualTo(value); 203 } 204 205 @Test getInt_invalid()206 public void getInt_invalid() { 207 final int default_value = 999; 208 DeviceConfig.setProperty(NAMESPACE, KEY, "not_an_int", false); 209 210 final int result = DeviceConfig.getInt(NAMESPACE, KEY, default_value); 211 // Failure to parse results in using the default value 212 assertThat(result).isEqualTo(default_value); 213 } 214 215 @Test getInt_nullNamespace()216 public void getInt_nullNamespace() { 217 try { 218 DeviceConfig.getInt(null, KEY, 0); 219 Assert.fail("Null namespace should have resulted in an NPE."); 220 } catch (NullPointerException e) { 221 // expected 222 } 223 } 224 225 @Test getInt_nullName()226 public void getInt_nullName() { 227 try { 228 DeviceConfig.getInt(NAMESPACE, null, 0); 229 Assert.fail("Null name should have resulted in an NPE."); 230 } catch (NullPointerException e) { 231 // expected 232 } 233 } 234 235 @Test getLong_empty()236 public void getLong_empty() { 237 final long default_value = 123456; 238 final long result = DeviceConfig.getLong(NAMESPACE, KEY, default_value); 239 assertThat(result).isEqualTo(default_value); 240 } 241 242 @Test getLong_valid()243 public void getLong_valid() { 244 final long value = 456789; 245 final long default_value = 123456; 246 DeviceConfig.setProperty(NAMESPACE, KEY, String.valueOf(value), false); 247 248 final long result = DeviceConfig.getLong(NAMESPACE, KEY, default_value); 249 assertThat(result).isEqualTo(value); 250 } 251 252 @Test getLong_invalid()253 public void getLong_invalid() { 254 final long default_value = 123456; 255 DeviceConfig.setProperty(NAMESPACE, KEY, "not_a_long", false); 256 257 final long result = DeviceConfig.getLong(NAMESPACE, KEY, default_value); 258 // Failure to parse results in using the default value 259 assertThat(result).isEqualTo(default_value); 260 } 261 262 @Test getLong_nullNamespace()263 public void getLong_nullNamespace() { 264 try { 265 DeviceConfig.getLong(null, KEY, 0); 266 Assert.fail("Null namespace should have resulted in an NPE."); 267 } catch (NullPointerException e) { 268 // expected 269 } 270 } 271 272 @Test getLong_nullName()273 public void getLong_nullName() { 274 try { 275 DeviceConfig.getLong(NAMESPACE, null, 0); 276 Assert.fail("Null name should have resulted in an NPE."); 277 } catch (NullPointerException e) { 278 // expected 279 } 280 } 281 282 @Test getFloat_empty()283 public void getFloat_empty() { 284 final float default_value = 123.456f; 285 final float result = DeviceConfig.getFloat(NAMESPACE, KEY, default_value); 286 assertThat(result).isEqualTo(default_value); 287 } 288 289 @Test getFloat_valid()290 public void getFloat_valid() { 291 final float value = 456.789f; 292 final float default_value = 123.456f; 293 DeviceConfig.setProperty(NAMESPACE, KEY, String.valueOf(value), false); 294 295 final float result = DeviceConfig.getFloat(NAMESPACE, KEY, default_value); 296 assertThat(result).isEqualTo(value); 297 } 298 299 @Test getFloat_invalid()300 public void getFloat_invalid() { 301 final float default_value = 123.456f; 302 DeviceConfig.setProperty(NAMESPACE, KEY, "not_a_float", false); 303 304 final float result = DeviceConfig.getFloat(NAMESPACE, KEY, default_value); 305 // Failure to parse results in using the default value 306 assertThat(result).isEqualTo(default_value); 307 } 308 309 @Test getFloat_nullNamespace()310 public void getFloat_nullNamespace() { 311 try { 312 DeviceConfig.getFloat(null, KEY, 0); 313 Assert.fail("Null namespace should have resulted in an NPE."); 314 } catch (NullPointerException e) { 315 // expected 316 } 317 } 318 319 @Test getFloat_nullName()320 public void getFloat_nullName() { 321 try { 322 DeviceConfig.getFloat(NAMESPACE, null, 0); 323 Assert.fail("Null name should have resulted in an NPE."); 324 } catch (NullPointerException e) { 325 // expected 326 } 327 } 328 329 @Test setProperty_nullNamespace()330 public void setProperty_nullNamespace() { 331 try { 332 DeviceConfig.setProperty(null, KEY, VALUE, false); 333 Assert.fail("Null namespace should have resulted in an NPE."); 334 } catch (NullPointerException e) { 335 // expected 336 } 337 } 338 339 @Test setProperty_nullName()340 public void setProperty_nullName() { 341 try { 342 DeviceConfig.setProperty(NAMESPACE, null, VALUE, false); 343 Assert.fail("Null name should have resulted in an NPE."); 344 } catch (NullPointerException e) { 345 // expected 346 } 347 } 348 349 @Test setAndGetProperty_sameNamespace()350 public void setAndGetProperty_sameNamespace() { 351 DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false); 352 String result = DeviceConfig.getProperty(NAMESPACE, KEY); 353 assertThat(result).isEqualTo(VALUE); 354 } 355 356 @Test setAndGetProperty_differentNamespace()357 public void setAndGetProperty_differentNamespace() { 358 String newNamespace = "namespace2"; 359 DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false); 360 String result = DeviceConfig.getProperty(newNamespace, KEY); 361 assertThat(result).isNull(); 362 } 363 364 @Test setAndGetProperty_multipleNamespaces()365 public void setAndGetProperty_multipleNamespaces() { 366 String newNamespace = "namespace2"; 367 String newValue = "value2"; 368 DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false); 369 DeviceConfig.setProperty(newNamespace, KEY, newValue, false); 370 String result = DeviceConfig.getProperty(NAMESPACE, KEY); 371 assertThat(result).isEqualTo(VALUE); 372 result = DeviceConfig.getProperty(newNamespace, KEY); 373 assertThat(result).isEqualTo(newValue); 374 375 // clean up 376 deleteViaContentProvider(newNamespace, KEY); 377 } 378 379 @Test setAndGetProperty_overrideValue()380 public void setAndGetProperty_overrideValue() { 381 String newValue = "value2"; 382 DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false); 383 DeviceConfig.setProperty(NAMESPACE, KEY, newValue, false); 384 String result = DeviceConfig.getProperty(NAMESPACE, KEY); 385 assertThat(result).isEqualTo(newValue); 386 } 387 388 @Test resetToDefault_makeDefault()389 public void resetToDefault_makeDefault() { 390 DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, true); 391 assertThat(DeviceConfig.getProperty(NAMESPACE, KEY)).isEqualTo(VALUE); 392 393 DeviceConfig.resetToDefaults(Settings.RESET_MODE_PACKAGE_DEFAULTS, NAMESPACE); 394 assertThat(DeviceConfig.getProperty(NAMESPACE, KEY)).isEqualTo(VALUE); 395 } 396 397 @Test resetToDefault_doNotMakeDefault()398 public void resetToDefault_doNotMakeDefault() { 399 DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false); 400 assertThat(DeviceConfig.getProperty(NAMESPACE, KEY)).isEqualTo(VALUE); 401 402 DeviceConfig.resetToDefaults(Settings.RESET_MODE_PACKAGE_DEFAULTS, NAMESPACE); 403 assertThat(DeviceConfig.getProperty(NAMESPACE, KEY)).isNull(); 404 } 405 406 @Test getProperties_fullNamespace()407 public void getProperties_fullNamespace() { 408 Properties properties = DeviceConfig.getProperties(NAMESPACE); 409 assertThat(properties.getKeyset()).isEmpty(); 410 411 DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false); 412 DeviceConfig.setProperty(NAMESPACE, KEY2, VALUE2, false); 413 properties = DeviceConfig.getProperties(NAMESPACE); 414 assertThat(properties.getKeyset()).containsExactly(KEY, KEY2); 415 assertThat(properties.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE); 416 assertThat(properties.getString(KEY2, DEFAULT_VALUE)).isEqualTo(VALUE2); 417 418 DeviceConfig.setProperty(NAMESPACE, KEY, VALUE3, false); 419 properties = DeviceConfig.getProperties(NAMESPACE); 420 assertThat(properties.getKeyset()).containsExactly(KEY, KEY2); 421 assertThat(properties.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE3); 422 assertThat(properties.getString(KEY2, DEFAULT_VALUE)).isEqualTo(VALUE2); 423 424 DeviceConfig.setProperty(NAMESPACE, KEY3, VALUE, false); 425 properties = DeviceConfig.getProperties(NAMESPACE); 426 assertThat(properties.getKeyset()).containsExactly(KEY, KEY2, KEY3); 427 assertThat(properties.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE3); 428 assertThat(properties.getString(KEY2, DEFAULT_VALUE)).isEqualTo(VALUE2); 429 assertThat(properties.getString(KEY3, DEFAULT_VALUE)).isEqualTo(VALUE); 430 } 431 432 @Test getProperties_getString()433 public void getProperties_getString() { 434 DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false); 435 DeviceConfig.setProperty(NAMESPACE, KEY2, VALUE2, false); 436 437 Properties properties = DeviceConfig.getProperties(NAMESPACE, KEY, KEY2); 438 assertThat(properties.getKeyset()).containsExactly(KEY, KEY2); 439 assertThat(properties.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE); 440 assertThat(properties.getString(KEY2, DEFAULT_VALUE)).isEqualTo(VALUE2); 441 } 442 443 @Test getProperties_getBoolean()444 public void getProperties_getBoolean() { 445 DeviceConfig.setProperty(NAMESPACE, KEY, "true", false); 446 DeviceConfig.setProperty(NAMESPACE, KEY2, "false", false); 447 DeviceConfig.setProperty(NAMESPACE, KEY3, "not a valid boolean", false); 448 449 Properties properties = DeviceConfig.getProperties(NAMESPACE, KEY, KEY2, KEY3); 450 assertThat(properties.getKeyset()).containsExactly(KEY, KEY2, KEY3); 451 assertThat(properties.getBoolean(KEY, true)).isTrue(); 452 assertThat(properties.getBoolean(KEY, false)).isTrue(); 453 assertThat(properties.getBoolean(KEY2, true)).isFalse(); 454 assertThat(properties.getBoolean(KEY2, false)).isFalse(); 455 // KEY3 was set to garbage, anything nonnull but "true" will parse as false 456 assertThat(properties.getBoolean(KEY3, true)).isFalse(); 457 assertThat(properties.getBoolean(KEY3, false)).isFalse(); 458 // If a key was not set, it will return the default value 459 assertThat(properties.getBoolean("missing_key", true)).isTrue(); 460 assertThat(properties.getBoolean("missing_key", false)).isFalse(); 461 } 462 463 @Test getProperties_getInt()464 public void getProperties_getInt() { 465 final int value = 101; 466 467 DeviceConfig.setProperty(NAMESPACE, KEY, Integer.toString(value), false); 468 DeviceConfig.setProperty(NAMESPACE, KEY2, "not a valid int", false); 469 470 Properties properties = DeviceConfig.getProperties(NAMESPACE, KEY, KEY2); 471 assertThat(properties.getKeyset()).containsExactly(KEY, KEY2); 472 assertThat(properties.getInt(KEY, -1)).isEqualTo(value); 473 // KEY2 was set to garbage, the default value is returned if an int cannot be parsed 474 assertThat(properties.getInt(KEY2, -1)).isEqualTo(-1); 475 } 476 477 @Test getProperties_getFloat()478 public void getProperties_getFloat() { 479 final float value = 101.010f; 480 481 DeviceConfig.setProperty(NAMESPACE, KEY, Float.toString(value), false); 482 DeviceConfig.setProperty(NAMESPACE, KEY2, "not a valid float", false); 483 484 Properties properties = DeviceConfig.getProperties(NAMESPACE, KEY, KEY2); 485 assertThat(properties.getKeyset()).containsExactly(KEY, KEY2); 486 assertThat(properties.getFloat(KEY, -1.0f)).isEqualTo(value); 487 // KEY2 was set to garbage, the default value is returned if a float cannot be parsed 488 assertThat(properties.getFloat(KEY2, -1.0f)).isEqualTo(-1.0f); 489 } 490 491 @Test getProperties_getLong()492 public void getProperties_getLong() { 493 final long value = 101; 494 495 DeviceConfig.setProperty(NAMESPACE, KEY, Long.toString(value), false); 496 DeviceConfig.setProperty(NAMESPACE, KEY2, "not a valid long", false); 497 498 Properties properties = DeviceConfig.getProperties(NAMESPACE, KEY, KEY2); 499 assertThat(properties.getKeyset()).containsExactly(KEY, KEY2); 500 assertThat(properties.getLong(KEY, -1)).isEqualTo(value); 501 // KEY2 was set to garbage, the default value is returned if a long cannot be parsed 502 assertThat(properties.getLong(KEY2, -1)).isEqualTo(-1); 503 } 504 505 @Test getProperties_defaults()506 public void getProperties_defaults() { 507 DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false); 508 DeviceConfig.setProperty(NAMESPACE, KEY3, VALUE3, false); 509 510 Properties properties = DeviceConfig.getProperties(NAMESPACE, KEY, KEY2); 511 assertThat(properties.getKeyset()).containsExactly(KEY); 512 assertThat(properties.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE); 513 // not set in DeviceConfig, but requested in getProperties 514 assertThat(properties.getString(KEY2, DEFAULT_VALUE)).isEqualTo(DEFAULT_VALUE); 515 // set in DeviceConfig, but not requested in getProperties 516 assertThat(properties.getString(KEY3, DEFAULT_VALUE)).isEqualTo(DEFAULT_VALUE); 517 } 518 519 @Test setProperties()520 public void setProperties() throws DeviceConfig.BadConfigException { 521 Properties properties = new Properties.Builder(NAMESPACE).setString(KEY, VALUE) 522 .setString(KEY2, VALUE2).build(); 523 524 DeviceConfig.setProperties(properties); 525 properties = DeviceConfig.getProperties(NAMESPACE); 526 assertThat(properties.getKeyset()).containsExactly(KEY, KEY2); 527 assertThat(properties.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE); 528 assertThat(properties.getString(KEY2, DEFAULT_VALUE)).isEqualTo(VALUE2); 529 530 properties = new Properties.Builder(NAMESPACE).setString(KEY, VALUE2) 531 .setString(KEY3, VALUE3).build(); 532 533 DeviceConfig.setProperties(properties); 534 properties = DeviceConfig.getProperties(NAMESPACE); 535 assertThat(properties.getKeyset()).containsExactly(KEY, KEY3); 536 assertThat(properties.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE2); 537 assertThat(properties.getString(KEY3, DEFAULT_VALUE)).isEqualTo(VALUE3); 538 539 assertThat(properties.getKeyset()).doesNotContain(KEY2); 540 assertThat(properties.getString(KEY2, DEFAULT_VALUE)).isEqualTo(DEFAULT_VALUE); 541 } 542 543 @Test setProperties_multipleNamespaces()544 public void setProperties_multipleNamespaces() throws DeviceConfig.BadConfigException { 545 final String namespace2 = "namespace2"; 546 Properties properties1 = new Properties.Builder(NAMESPACE).setString(KEY, VALUE) 547 .setString(KEY2, VALUE2).build(); 548 Properties properties2 = new Properties.Builder(namespace2).setString(KEY2, VALUE) 549 .setString(KEY3, VALUE2).build(); 550 551 DeviceConfig.setProperties(properties1); 552 DeviceConfig.setProperties(properties2); 553 554 Properties properties = DeviceConfig.getProperties(NAMESPACE); 555 assertThat(properties.getKeyset()).containsExactly(KEY, KEY2); 556 assertThat(properties.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE); 557 assertThat(properties.getString(KEY2, DEFAULT_VALUE)).isEqualTo(VALUE2); 558 559 assertThat(properties.getKeyset()).doesNotContain(KEY3); 560 assertThat(properties.getString(KEY3, DEFAULT_VALUE)).isEqualTo(DEFAULT_VALUE); 561 562 properties = DeviceConfig.getProperties(namespace2); 563 assertThat(properties.getKeyset()).containsExactly(KEY2, KEY3); 564 assertThat(properties.getString(KEY2, DEFAULT_VALUE)).isEqualTo(VALUE); 565 assertThat(properties.getString(KEY3, DEFAULT_VALUE)).isEqualTo(VALUE2); 566 567 assertThat(properties.getKeyset()).doesNotContain(KEY); 568 assertThat(properties.getString(KEY, DEFAULT_VALUE)).isEqualTo(DEFAULT_VALUE); 569 570 // clean up 571 deleteViaContentProvider(namespace2, KEY); 572 deleteViaContentProvider(namespace2, KEY2); 573 deleteViaContentProvider(namespace2, KEY3); 574 } 575 576 @Test propertiesBuilder()577 public void propertiesBuilder() { 578 boolean booleanValue = true; 579 int intValue = 123; 580 float floatValue = 4.56f; 581 long longValue = -789L; 582 String key4 = "key4"; 583 String key5 = "key5"; 584 585 Properties properties = new Properties.Builder(NAMESPACE).setString(KEY, VALUE) 586 .setBoolean(KEY2, booleanValue).setInt(KEY3, intValue).setLong(key4, longValue) 587 .setFloat(key5, floatValue).build(); 588 assertThat(properties.getNamespace()).isEqualTo(NAMESPACE); 589 assertThat(properties.getString(KEY, "defaultValue")).isEqualTo(VALUE); 590 assertThat(properties.getBoolean(KEY2, false)).isEqualTo(booleanValue); 591 assertThat(properties.getInt(KEY3, 0)).isEqualTo(intValue); 592 assertThat(properties.getLong("key4", 0L)).isEqualTo(longValue); 593 assertThat(properties.getFloat("key5", 0f)).isEqualTo(floatValue); 594 } 595 596 @Test banNamespaceProperties()597 public void banNamespaceProperties() throws DeviceConfig.BadConfigException { 598 // Given namespace will be permanently banned, thus it needs to be different every time 599 final String namespaceToBan = NAMESPACE + System.currentTimeMillis(); 600 Properties properties = new Properties.Builder(namespaceToBan).setString(KEY, VALUE) 601 .setString(KEY4, NULL_VALUE).build(); 602 // Set namespace properties 603 DeviceConfig.setProperties(properties); 604 // Ban namespace with related properties 605 DeviceConfig.resetToDefaults(Settings.RESET_MODE_PACKAGE_DEFAULTS, namespaceToBan); 606 // Verify given namespace properties are banned 607 assertThrows(DeviceConfig.BadConfigException.class, 608 () -> DeviceConfig.setProperties(properties)); 609 // Modify properties and verify we can set them 610 Properties modifiedProperties = new Properties.Builder(namespaceToBan).setString(KEY, VALUE) 611 .setString(KEY4, NULL_VALUE).setString(KEY2, VALUE2).build(); 612 DeviceConfig.setProperties(modifiedProperties); 613 modifiedProperties = DeviceConfig.getProperties(namespaceToBan); 614 assertThat(modifiedProperties.getKeyset()).containsExactly(KEY, KEY2, KEY4); 615 assertThat(modifiedProperties.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE); 616 assertThat(modifiedProperties.getString(KEY2, DEFAULT_VALUE)).isEqualTo(VALUE2); 617 // Since value is null DEFAULT_VALUE should be returned 618 assertThat(modifiedProperties.getString(KEY4, DEFAULT_VALUE)).isEqualTo(DEFAULT_VALUE); 619 } 620 621 @Test banEntireDeviceConfig()622 public void banEntireDeviceConfig() throws DeviceConfig.BadConfigException { 623 // Given namespaces will be permanently banned, thus they need to be different every time 624 final String namespaceToBan1 = NAMESPACE + System.currentTimeMillis(); 625 final String namespaceToBan2 = NAMESPACE + System.currentTimeMillis() + 1; 626 627 // Set namespaces properties 628 Properties properties1 = new Properties.Builder(namespaceToBan1).setString(KEY, VALUE) 629 .setString(KEY4, NULL_VALUE).build(); 630 DeviceConfig.setProperties(properties1); 631 Properties properties2 = new Properties.Builder(namespaceToBan2).setString(KEY2, VALUE2) 632 .setString(KEY4, NULL_VALUE).build(); 633 DeviceConfig.setProperties(properties2); 634 635 // Ban entire DeviceConfig 636 DeviceConfig.resetToDefaults(Settings.RESET_MODE_PACKAGE_DEFAULTS, null); 637 638 // Verify given namespace properties are banned 639 assertThrows(DeviceConfig.BadConfigException.class, 640 () -> DeviceConfig.setProperties(properties1)); 641 assertThrows(DeviceConfig.BadConfigException.class, 642 () -> DeviceConfig.setProperties(properties2)); 643 644 // Modify properties and verify we can set them 645 Properties modifiedProperties1 = new Properties.Builder(namespaceToBan1).setString(KEY, 646 VALUE) 647 .setString(KEY4, NULL_VALUE).setString(KEY2, VALUE2).build(); 648 DeviceConfig.setProperties(modifiedProperties1); 649 modifiedProperties1 = DeviceConfig.getProperties(namespaceToBan1); 650 assertThat(modifiedProperties1.getKeyset()).containsExactly(KEY, KEY2, KEY4); 651 assertThat(modifiedProperties1.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE); 652 assertThat(modifiedProperties1.getString(KEY2, DEFAULT_VALUE)).isEqualTo(VALUE2); 653 // Since value is null DEFAULT_VALUE should be returned 654 assertThat(modifiedProperties1.getString(KEY4, DEFAULT_VALUE)).isEqualTo(DEFAULT_VALUE); 655 656 Properties modifiedProperties2 = new Properties.Builder(namespaceToBan2).setString(KEY, 657 VALUE) 658 .setString(KEY3, NULL_VALUE).setString(KEY4, VALUE2).build(); 659 DeviceConfig.setProperties(modifiedProperties2); 660 modifiedProperties2 = DeviceConfig.getProperties(namespaceToBan2); 661 assertThat(modifiedProperties2.getKeyset()).containsExactly(KEY, KEY3, KEY4); 662 assertThat(modifiedProperties2.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE); 663 assertThat(modifiedProperties2.getString(KEY4, DEFAULT_VALUE)).isEqualTo(VALUE2); 664 // Since value is null DEFAULT_VALUE should be returned 665 assertThat(modifiedProperties2.getString(KEY3, DEFAULT_VALUE)).isEqualTo(DEFAULT_VALUE); 666 } 667 668 @Test allConfigsUnbannedIfAnyUnbannedConfigUpdated()669 public void allConfigsUnbannedIfAnyUnbannedConfigUpdated() 670 throws DeviceConfig.BadConfigException { 671 // Given namespaces will be permanently banned, thus they need to be different every time 672 final String namespaceToBan1 = NAMESPACE + System.currentTimeMillis(); 673 final String namespaceToBan2 = NAMESPACE + System.currentTimeMillis() + 1; 674 675 // Set namespaces properties 676 Properties properties1 = new Properties.Builder(namespaceToBan1).setString(KEY, VALUE) 677 .setString(KEY4, NULL_VALUE).build(); 678 DeviceConfig.setProperties(properties1); 679 Properties properties2 = new Properties.Builder(namespaceToBan2).setString(KEY2, VALUE2) 680 .setString(KEY4, NULL_VALUE).build(); 681 DeviceConfig.setProperties(properties2); 682 683 // Ban namespace with related properties 684 DeviceConfig.resetToDefaults(Settings.RESET_MODE_PACKAGE_DEFAULTS, namespaceToBan1); 685 DeviceConfig.resetToDefaults(Settings.RESET_MODE_PACKAGE_DEFAULTS, namespaceToBan2); 686 687 // Verify given namespace properties are banned 688 assertThrows(DeviceConfig.BadConfigException.class, 689 () -> DeviceConfig.setProperties(properties1)); 690 assertThrows(DeviceConfig.BadConfigException.class, 691 () -> DeviceConfig.setProperties(properties2)); 692 693 // Modify properties and verify we can set them 694 Properties modifiedProperties1 = new Properties.Builder(namespaceToBan1).setString(KEY, 695 VALUE) 696 .setString(KEY4, NULL_VALUE).setString(KEY2, VALUE2).build(); 697 DeviceConfig.setProperties(modifiedProperties1); 698 modifiedProperties1 = DeviceConfig.getProperties(namespaceToBan1); 699 assertThat(modifiedProperties1.getKeyset()).containsExactly(KEY, KEY2, KEY4); 700 assertThat(modifiedProperties1.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE); 701 assertThat(modifiedProperties1.getString(KEY2, DEFAULT_VALUE)).isEqualTo(VALUE2); 702 // Since value is null DEFAULT_VALUE should be returned 703 assertThat(modifiedProperties1.getString(KEY4, DEFAULT_VALUE)).isEqualTo(DEFAULT_VALUE); 704 705 // verify that other banned namespaces are unbanned now. 706 DeviceConfig.setProperties(properties2); 707 Properties result = DeviceConfig.getProperties(namespaceToBan2); 708 assertThat(result.getKeyset()).containsExactly(KEY2, KEY4); 709 assertThat(result.getString(KEY2, DEFAULT_VALUE)).isEqualTo(VALUE2); 710 // Since value is null DEFAULT_VALUE should be returned 711 assertThat(result.getString(KEY4, DEFAULT_VALUE)).isEqualTo(DEFAULT_VALUE); 712 } 713 714 @Test onPropertiesChangedListener_setPropertyCallback()715 public void onPropertiesChangedListener_setPropertyCallback() throws InterruptedException { 716 final AtomicReference<Properties> changedProperties = new AtomicReference<>(); 717 final CompletableFuture<Boolean> completed = new CompletableFuture<>(); 718 719 DeviceConfig.OnPropertiesChangedListener changeListener = (properties) -> { 720 changedProperties.set(properties); 721 completed.complete(true); 722 }; 723 724 try { 725 DeviceConfig.addOnPropertiesChangedListener(NAMESPACE, 726 Objects.requireNonNull(ActivityThread.currentApplication()).getMainExecutor(), 727 changeListener); 728 DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false); 729 730 assertThat(completed.get( 731 WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue(); 732 733 Properties properties = changedProperties.get(); 734 assertThat(properties.getNamespace()).isEqualTo(NAMESPACE); 735 assertThat(properties.getKeyset()).contains(KEY); 736 assertThat(properties.getString(KEY, "default_value")).isEqualTo(VALUE); 737 } catch (ExecutionException | TimeoutException | InterruptedException e) { 738 Assert.fail(e.getMessage()); 739 } finally { 740 DeviceConfig.removeOnPropertiesChangedListener(changeListener); 741 } 742 } 743 744 @Test onPropertiesChangedListener_setPropertiesCallback()745 public void onPropertiesChangedListener_setPropertiesCallback() { 746 DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false); 747 DeviceConfig.setProperty(NAMESPACE, KEY2, VALUE2, false); 748 749 Map<String, String> keyValues = new HashMap<>(2); 750 keyValues.put(KEY, VALUE2); 751 keyValues.put(KEY3, VALUE3); 752 Properties setProperties = new Properties(NAMESPACE, keyValues); 753 754 final AtomicReference<Properties> changedProperties = new AtomicReference<>(); 755 final CompletableFuture<Boolean> completed = new CompletableFuture<>(); 756 757 DeviceConfig.OnPropertiesChangedListener changeListener = (properties) -> { 758 changedProperties.set(properties); 759 completed.complete(true); 760 }; 761 762 try { 763 DeviceConfig.addOnPropertiesChangedListener(NAMESPACE, 764 Objects.requireNonNull(ActivityThread.currentApplication()).getMainExecutor(), 765 changeListener); 766 DeviceConfig.setProperties(setProperties); 767 768 assertThat(completed.get( 769 WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue(); 770 771 if (changedProperties.get().getKeyset().size() != 3) { 772 // Sometimes there are a few onChanged callback calls. Let's wait a bit more. 773 final int oneMoreOnChangedDelayMs = 100; 774 Thread.currentThread().sleep(oneMoreOnChangedDelayMs); 775 } 776 777 Properties properties = changedProperties.get(); 778 assertThat(properties.getNamespace()).isEqualTo(NAMESPACE); 779 assertThat(properties.getKeyset()).containsExactly(KEY, KEY2, KEY3); 780 // KEY updated from VALUE to VALUE2 781 assertThat(properties.getString(KEY, "default_value")).isEqualTo(VALUE2); 782 // KEY2 deleted (returns default_value) 783 assertThat(properties.getString(KEY2, "default_value")).isEqualTo("default_value"); 784 // KEY3 added with VALUE3 785 assertThat(properties.getString(KEY3, "default_value")).isEqualTo(VALUE3); 786 } catch (ExecutionException | TimeoutException | InterruptedException e) { 787 Assert.fail(e.getMessage()); 788 } catch (DeviceConfig.BadConfigException e) { 789 Assert.fail(e.getMessage()); 790 } finally { 791 DeviceConfig.removeOnPropertiesChangedListener(changeListener); 792 } 793 } 794 795 @Test syncDisabling()796 public void syncDisabling() throws Exception { 797 Properties properties1 = new Properties.Builder(NAMESPACE) 798 .setString(KEY, VALUE) 799 .build(); 800 Properties properties2 = new Properties.Builder(NAMESPACE) 801 .setString(KEY, VALUE2) 802 .build(); 803 804 try { 805 // Ensure the device starts in a known state. 806 DeviceConfig.setSyncDisabledMode(DeviceConfig.SYNC_DISABLED_MODE_NONE); 807 808 // Assert starting state. 809 assertThat(DeviceConfig.getSyncDisabledMode()) 810 .isEqualTo(DeviceConfig.SYNC_DISABLED_MODE_NONE); 811 assertThat(DeviceConfig.setProperties(properties1)).isTrue(); 812 assertThat(DeviceConfig.getProperties(NAMESPACE, KEY).getString(KEY, DEFAULT_VALUE)) 813 .isEqualTo(VALUE); 814 815 // Test disabled (persistent). Persistence is not actually tested, that would require 816 // a host test. 817 DeviceConfig.setSyncDisabledMode(DeviceConfig.SYNC_DISABLED_MODE_PERSISTENT); 818 assertThat(DeviceConfig.getSyncDisabledMode()) 819 .isEqualTo(DeviceConfig.SYNC_DISABLED_MODE_PERSISTENT); 820 assertThat(DeviceConfig.setProperties(properties2)).isFalse(); 821 assertThat(DeviceConfig.getProperties(NAMESPACE, KEY).getString(KEY, DEFAULT_VALUE)) 822 .isEqualTo(VALUE); 823 824 // Return to not disabled. 825 DeviceConfig.setSyncDisabledMode(DeviceConfig.SYNC_DISABLED_MODE_NONE); 826 assertThat(DeviceConfig.getSyncDisabledMode()) 827 .isEqualTo(DeviceConfig.SYNC_DISABLED_MODE_NONE); 828 assertThat(DeviceConfig.setProperties(properties2)).isTrue(); 829 assertThat(DeviceConfig.getProperties(NAMESPACE, KEY).getString(KEY, DEFAULT_VALUE)) 830 .isEqualTo(VALUE2); 831 832 // Test disabled (persistent). Absence of persistence is not actually tested, that would 833 // require a host test. 834 DeviceConfig.setSyncDisabledMode(DeviceConfig.SYNC_DISABLED_MODE_UNTIL_REBOOT); 835 assertThat(DeviceConfig.getSyncDisabledMode()) 836 .isEqualTo(DeviceConfig.SYNC_DISABLED_MODE_UNTIL_REBOOT); 837 assertThat(DeviceConfig.setProperties(properties1)).isFalse(); 838 assertThat(DeviceConfig.getProperties(NAMESPACE, KEY).getString(KEY, DEFAULT_VALUE)) 839 .isEqualTo(VALUE2); 840 841 // Return to not disabled. 842 DeviceConfig.setSyncDisabledMode(DeviceConfig.SYNC_DISABLED_MODE_NONE); 843 assertThat(DeviceConfig.getSyncDisabledMode()) 844 .isEqualTo(DeviceConfig.SYNC_DISABLED_MODE_NONE); 845 assertThat(DeviceConfig.setProperties(properties1)).isTrue(); 846 assertThat(DeviceConfig.getProperties(NAMESPACE, KEY).getString(KEY, DEFAULT_VALUE)) 847 .isEqualTo(VALUE); 848 } finally { 849 // Try to return to the default sync disabled state in case of failure. 850 DeviceConfig.setSyncDisabledMode(DeviceConfig.SYNC_DISABLED_MODE_NONE); 851 852 // NAMESPACE will be cleared by cleanUp() 853 } 854 } 855 deleteViaContentProvider(String namespace, String key)856 private static boolean deleteViaContentProvider(String namespace, String key) { 857 ContentResolver resolver = InstrumentationRegistry.getContext().getContentResolver(); 858 String compositeName = namespace + "/" + key; 859 Bundle result = resolver.call( 860 Settings.Config.CONTENT_URI, 861 Settings.CALL_METHOD_DELETE_CONFIG, 862 compositeName, 863 null); 864 assertThat(result).isNotNull(); 865 return compositeName.equals(result.getString(Settings.NameValueTable.VALUE)); 866 } 867 868 @Test deleteProperty_nullNamespace()869 public void deleteProperty_nullNamespace() { 870 try { 871 DeviceConfig.deleteProperty(null, KEY); 872 Assert.fail("Null namespace should have resulted in an NPE."); 873 } catch (NullPointerException e) { 874 // expected 875 } 876 } 877 878 @Test deleteProperty_nullName()879 public void deleteProperty_nullName() { 880 try { 881 DeviceConfig.deleteProperty(NAMESPACE, null); 882 Assert.fail("Null name should have resulted in an NPE."); 883 } catch (NullPointerException e) { 884 // expected 885 } 886 } 887 888 @Test deletePropertyString()889 public void deletePropertyString() { 890 final String value = "new_value"; 891 final String default_value = "default"; 892 DeviceConfig.setProperty(NAMESPACE, KEY, value, false); 893 DeviceConfig.deleteProperty(NAMESPACE, KEY); 894 final String result = DeviceConfig.getString(NAMESPACE, KEY, default_value); 895 assertThat(result).isEqualTo(default_value); 896 } 897 898 @Test deletePropertyBoolean()899 public void deletePropertyBoolean() { 900 final boolean value = true; 901 final boolean default_value = false; 902 DeviceConfig.setProperty(NAMESPACE, KEY, String.valueOf(value), false); 903 DeviceConfig.deleteProperty(NAMESPACE, KEY); 904 final boolean result = DeviceConfig.getBoolean(NAMESPACE, KEY, default_value); 905 assertThat(result).isEqualTo(default_value); 906 } 907 908 @Test deletePropertyInt()909 public void deletePropertyInt() { 910 final int value = 123; 911 final int default_value = 999; 912 DeviceConfig.setProperty(NAMESPACE, KEY, String.valueOf(value), false); 913 DeviceConfig.deleteProperty(NAMESPACE, KEY); 914 final int result = DeviceConfig.getInt(NAMESPACE, KEY, default_value); 915 assertThat(result).isEqualTo(default_value); 916 } 917 918 @Test deletePropertyLong()919 public void deletePropertyLong() { 920 final long value = 456789; 921 final long default_value = 123456; 922 DeviceConfig.setProperty(NAMESPACE, KEY, String.valueOf(value), false); 923 DeviceConfig.deleteProperty(NAMESPACE, KEY); 924 final long result = DeviceConfig.getLong(NAMESPACE, KEY, default_value); 925 assertThat(result).isEqualTo(default_value); 926 } 927 928 @Test deletePropertyFloat()929 public void deletePropertyFloat() { 930 final float value = 456.789f; 931 final float default_value = 123.456f; 932 DeviceConfig.setProperty(NAMESPACE, KEY, String.valueOf(value), false); 933 DeviceConfig.deleteProperty(NAMESPACE, KEY); 934 final float result = DeviceConfig.getFloat(NAMESPACE, KEY, default_value); 935 assertThat(result).isEqualTo(default_value); 936 } 937 938 @Test deleteProperty_empty()939 public void deleteProperty_empty() { 940 assertThat(DeviceConfig.deleteProperty(NAMESPACE, KEY)).isTrue(); 941 final String result = DeviceConfig.getString(NAMESPACE, KEY, null); 942 assertThat(result).isNull(); 943 } 944 } 945