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