1 /*
2  * Copyright (C) 2015 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 com.android.providers.settings;
18 
19 import static junit.framework.Assert.assertEquals;
20 import static junit.framework.Assert.assertNull;
21 import static junit.framework.Assert.assertSame;
22 import static junit.framework.Assert.fail;
23 
24 import android.content.ContentResolver;
25 import android.content.ContentValues;
26 import android.database.ContentObserver;
27 import android.database.Cursor;
28 import android.net.Uri;
29 import android.os.Handler;
30 import android.os.Looper;
31 import android.os.SystemClock;
32 import android.os.UserHandle;
33 import android.provider.Settings;
34 import android.util.Log;
35 
36 import org.junit.Test;
37 
38 import java.util.concurrent.atomic.AtomicBoolean;
39 
40 /**
41  * Tests for the SettingContentProvider.
42  *
43  * Before you run this test you must add a secondary user.
44  */
45 public class SettingsProviderTest extends BaseSettingsProviderTest {
46     private static final String LOG_TAG = "SettingsProviderTest";
47 
48     private static final long WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS = 2000; // 2 sec
49 
50     private static final String[] NAME_VALUE_COLUMNS = new String[]{
51             Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE
52     };
53 
54     private final Object mLock = new Object();
55 
56     @Test
testSetAndGetGlobalViaFrontEndApiForSystemUser()57     public void testSetAndGetGlobalViaFrontEndApiForSystemUser() throws Exception {
58         performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
59     }
60 
61     @Test
testSetAndGetGlobalViaFrontEndApiForNonSystemUser()62     public void testSetAndGetGlobalViaFrontEndApiForNonSystemUser() throws Exception {
63         final int secondaryUserId = getSecondaryUserId();
64         if (secondaryUserId == UserHandle.USER_SYSTEM) {
65             Log.w(LOG_TAG, "No secondary user. Skipping "
66                     + "testSetAndGetGlobalViaFrontEndApiForNonSystemUser");
67             return;
68         }
69         performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, secondaryUserId);
70     }
71 
72     @Test
testSetAndGetSecureViaFrontEndApiForSystemUser()73     public void testSetAndGetSecureViaFrontEndApiForSystemUser() throws Exception {
74         performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, UserHandle.USER_SYSTEM);
75     }
76 
77     @Test
testSetAndGetSecureViaFrontEndApiForNonSystemUser()78     public void testSetAndGetSecureViaFrontEndApiForNonSystemUser() throws Exception {
79         final int secondaryUserId = getSecondaryUserId();
80         if (secondaryUserId == UserHandle.USER_SYSTEM) {
81             Log.w(LOG_TAG, "No secondary user. Skipping "
82                     + "testSetAndGetSecureViaFrontEndApiForNonSystemUser");
83             return;
84         }
85         performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, secondaryUserId);
86     }
87 
88     @Test
testSetAndGetSystemViaFrontEndApiForSystemUser()89     public void testSetAndGetSystemViaFrontEndApiForSystemUser() throws Exception {
90         performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, UserHandle.USER_SYSTEM);
91     }
92 
93     @Test
testSetAndGetSystemViaFrontEndApiForNonSystemUser()94     public void testSetAndGetSystemViaFrontEndApiForNonSystemUser() throws Exception {
95         final int secondaryUserId = getSecondaryUserId();
96         if (secondaryUserId == UserHandle.USER_SYSTEM) {
97             Log.w(LOG_TAG, "No secondary user. Skipping "
98                     + "testSetAndGetSystemViaFrontEndApiForNonSystemUser");
99             return;
100         }
101         performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, secondaryUserId);
102     }
103 
104     @Test
testSetAndGetGlobalViaProviderApi()105     public void testSetAndGetGlobalViaProviderApi() throws Exception {
106         performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_GLOBAL);
107     }
108 
109     @Test
testSetAndGetSecureViaProviderApi()110     public void testSetAndGetSecureViaProviderApi() throws Exception {
111         performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_SECURE);
112     }
113 
114     @Test
testSetAndGetSystemViaProviderApi()115     public void testSetAndGetSystemViaProviderApi() throws Exception {
116         performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_SYSTEM);
117     }
118 
119     @Test
testSelectAllGlobalViaProviderApi()120     public void testSelectAllGlobalViaProviderApi() throws Exception {
121         setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_GLOBAL,
122                 FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
123         try {
124             queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_GLOBAL,
125                     FAKE_SETTING_NAME);
126         } finally {
127             deleteStringViaProviderApi(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME);
128         }
129     }
130 
131     // TODO(b/142206242): make this less flaky and re-enable it
132 //    @Test
133 //    public void testSelectAllSecureViaProviderApi() throws Exception {
134 //        setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_SECURE,
135 //                FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
136 //        try {
137 //            queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_SECURE,
138 //                    FAKE_SETTING_NAME);
139 //        } finally {
140 //            deleteStringViaProviderApi(SETTING_TYPE_SECURE, FAKE_SETTING_NAME);
141 //        }
142 //    }
143 
144     @Test
testSelectAllSystemViaProviderApi()145     public void testSelectAllSystemViaProviderApi() throws Exception {
146         setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_SYSTEM,
147                 FAKE_SETTING_NAME, FAKE_SETTING_VALUE, true);
148         try {
149             queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_SYSTEM,
150                     FAKE_SETTING_NAME);
151         } finally {
152             deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME);
153         }
154     }
155 
156     @Test
testQueryUpdateDeleteGlobalViaProviderApi()157     public void testQueryUpdateDeleteGlobalViaProviderApi() throws Exception {
158         doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_GLOBAL);
159     }
160 
161     @Test
testQueryUpdateDeleteSecureViaProviderApi()162     public void testQueryUpdateDeleteSecureViaProviderApi() throws Exception {
163         doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_SECURE);
164     }
165 
166     @Test
testQueryUpdateDeleteSystemViaProviderApi()167     public void testQueryUpdateDeleteSystemViaProviderApi() throws Exception {
168         doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_SYSTEM);
169     }
170 
171     @Test
testBulkInsertGlobalViaProviderApi()172     public void testBulkInsertGlobalViaProviderApi() throws Exception {
173         toTestBulkInsertViaProviderApiForType(SETTING_TYPE_GLOBAL);
174     }
175 
176     @Test
testBulkInsertSystemViaProviderApi()177     public void testBulkInsertSystemViaProviderApi() throws Exception {
178         toTestBulkInsertViaProviderApiForType(SETTING_TYPE_SYSTEM);
179     }
180 
181     @Test
testBulkInsertSecureViaProviderApi()182     public void testBulkInsertSecureViaProviderApi() throws Exception {
183         toTestBulkInsertViaProviderApiForType(SETTING_TYPE_SECURE);
184     }
185 
186     @Test
testAppCannotRunsSystemOutOfMemoryWritingSystemSettings()187     public void testAppCannotRunsSystemOutOfMemoryWritingSystemSettings() throws Exception {
188         int insertedCount = 0;
189         try {
190             for (; insertedCount < 1200; insertedCount++) {
191                 insertStringViaProviderApi(SETTING_TYPE_SYSTEM,
192                         String.valueOf(insertedCount), FAKE_SETTING_VALUE, false);
193             }
194             fail("Adding app specific settings must be bound.");
195         } catch (Exception e) {
196             // expected
197         } finally {
198             for (; insertedCount >= 0; insertedCount--) {
199                 deleteStringViaProviderApi(SETTING_TYPE_SYSTEM,
200                         String.valueOf(insertedCount));
201             }
202         }
203     }
204 
205     @Test
testQueryStringInBracketsGlobalViaProviderApiForType()206     public void testQueryStringInBracketsGlobalViaProviderApiForType() throws Exception {
207         doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_GLOBAL);
208     }
209 
210     @Test
testQueryStringInBracketsSecureViaProviderApiForType()211     public void testQueryStringInBracketsSecureViaProviderApiForType() throws Exception {
212         doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_SECURE);
213     }
214 
215     @Test
testQueryStringInBracketsSystemViaProviderApiForType()216     public void testQueryStringInBracketsSystemViaProviderApiForType() throws Exception {
217         doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_SYSTEM);
218     }
219 
220     @Test
testQueryStringWithAppendedNameToUriViaProviderApi()221     public void testQueryStringWithAppendedNameToUriViaProviderApi() throws Exception {
222         // Make sure we have a clean slate.
223         deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME);
224 
225         try {
226             // Insert the setting.
227             final Uri uri = insertStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME,
228                     FAKE_SETTING_VALUE, false);
229             Uri expectUri = Uri.withAppendedPath(getBaseUriForType(SETTING_TYPE_SYSTEM),
230                     FAKE_SETTING_NAME);
231             assertEquals("Did not get expected Uri.", expectUri, uri);
232 
233             // Make sure the first setting is there.
234             String firstValue = queryStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME,
235                     false, true);
236             assertEquals("Setting must be present", FAKE_SETTING_VALUE, firstValue);
237         } finally {
238             // Clean up.
239             deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME);
240         }
241     }
242 
243     @Test
testResetModePackageDefaultsGlobal()244     public void testResetModePackageDefaultsGlobal() throws Exception {
245         testResetModePackageDefaultsCommon(SETTING_TYPE_GLOBAL);
246     }
247 
248     @Test
testResetModePackageDefaultsSecure()249     public void testResetModePackageDefaultsSecure() throws Exception {
250         testResetModePackageDefaultsCommon(SETTING_TYPE_SECURE);
251     }
252 
testResetModePackageDefaultsCommon(int type)253     private void testResetModePackageDefaultsCommon(int type) throws Exception {
254         // Make sure we have a clean slate.
255         setSettingViaShell(type, FAKE_SETTING_NAME, null, true);
256         try {
257             // Set a value but don't make it the default
258             setSettingViaShell(type, FAKE_SETTING_NAME,
259                     FAKE_SETTING_VALUE, false);
260 
261             // Reset the changes made by the "shell/root" package
262             resetToDefaultsViaShell(type, "com.android.shell");
263             resetToDefaultsViaShell(type, "root");
264 
265             // Make sure the old APIs don't set defaults
266             assertNull(getSetting(type, FAKE_SETTING_NAME));
267 
268             // Set a value and make it the default
269             setSettingViaShell(type, FAKE_SETTING_NAME,
270                     FAKE_SETTING_VALUE, true);
271             // Change the setting from the default
272             setSettingViaShell(type, FAKE_SETTING_NAME,
273                     FAKE_SETTING_VALUE_2, false);
274 
275             // Reset the changes made by this package
276             resetToDefaultsViaShell(type, "com.android.shell");
277             resetToDefaultsViaShell(type, "root");
278 
279             // Make sure the old APIs don't set defaults
280             assertEquals(FAKE_SETTING_VALUE, getSetting(type, FAKE_SETTING_NAME));
281         } finally {
282             // Make sure we have a clean slate.
283             setSettingViaShell(type, FAKE_SETTING_NAME, null, true);
284         }
285     }
286 
287     @Test
testResetModePackageDefaultsWithTokensGlobal()288     public void testResetModePackageDefaultsWithTokensGlobal() throws Exception {
289         testResetModePackageDefaultsWithTokensCommon(SETTING_TYPE_GLOBAL);
290     }
291 
292     @Test
testResetModePackageDefaultsWithTokensSecure()293     public void testResetModePackageDefaultsWithTokensSecure() throws Exception {
294         testResetModePackageDefaultsWithTokensCommon(SETTING_TYPE_SECURE);
295     }
296 
testResetModePackageDefaultsWithTokensCommon(int type)297     private void testResetModePackageDefaultsWithTokensCommon(int type) throws Exception {
298         // Make sure we have a clean slate.
299         setSettingViaShell(type, FAKE_SETTING_NAME, null, true);
300         setSettingViaShell(type, FAKE_SETTING_NAME_1, null, true);
301         try {
302             // Set a default value
303             setSettingViaShell(type, FAKE_SETTING_NAME,
304                     FAKE_SETTING_VALUE, true);
305             // Change the default and associate a token
306             setSettingViaShell(type, FAKE_SETTING_NAME,
307                     FAKE_SETTING_VALUE_2, "TOKEN1", false);
308 
309             // Set a default value
310             setSettingViaShell(type, FAKE_SETTING_NAME_1,
311                     FAKE_SETTING_VALUE, "TOKEN2", true);
312             // Change the default and associate a token
313             setSettingViaShell(type, FAKE_SETTING_NAME_1,
314                     FAKE_SETTING_VALUE_2, "TOKEN2", false);
315 
316             // Reset settings associated with TOKEN1
317             resetToDefaultsViaShell(type, "com.android.shell", "TOKEN1");
318             resetToDefaultsViaShell(type, "root", "TOKEN1");
319 
320             // Make sure TOKEN1 settings are reset
321             assertEquals(FAKE_SETTING_VALUE, getSetting(type,
322                     FAKE_SETTING_NAME));
323 
324             // Make sure TOKEN2 settings are not reset
325             assertEquals(FAKE_SETTING_VALUE_2, getSetting(type,
326                     FAKE_SETTING_NAME_1));
327 
328             // Reset settings associated with TOKEN2
329             resetToDefaultsViaShell(type, "com.android.shell", "TOKEN2");
330             resetToDefaultsViaShell(type, "root", "TOKEN2");
331 
332             // Make sure TOKEN2 settings are reset
333             assertEquals(FAKE_SETTING_VALUE, getSetting(type,
334                     FAKE_SETTING_NAME_1));
335         } finally {
336             // Make sure we have a clean slate.
337             setSettingViaShell(type, FAKE_SETTING_NAME, null, true);
338             setSettingViaShell(type, FAKE_SETTING_NAME_1, null, true);
339         }
340     }
341 
342     @Test
testResetModeUntrustedDefaultsGlobal()343     public void testResetModeUntrustedDefaultsGlobal() throws Exception {
344         testResetModeUntrustedDefaultsCommon(SETTING_TYPE_GLOBAL);
345     }
346 
347     @Test
testResetModeUntrustedDefaultsSecure()348     public void testResetModeUntrustedDefaultsSecure() throws Exception {
349         testResetModeUntrustedDefaultsCommon(SETTING_TYPE_SECURE);
350     }
351 
testResetModeUntrustedDefaultsCommon(int type)352     private void testResetModeUntrustedDefaultsCommon(int type) throws Exception {
353         // Make sure we have a clean slate.
354         putSetting(type, FAKE_SETTING_NAME, null);
355         setSettingViaShell(type, FAKE_SETTING_NAME_1, null, true);
356         try {
357             // Set a default setting as a trusted component
358             putSetting(type, FAKE_SETTING_NAME, FAKE_SETTING_VALUE);
359             // Change the setting as a trusted component
360             putSetting(type, FAKE_SETTING_NAME, FAKE_SETTING_VALUE_2);
361 
362             // Set a default setting as an untrusted component
363             setSettingViaShell(type, FAKE_SETTING_NAME_1,
364                     FAKE_SETTING_VALUE, true);
365             // Change the setting as an untrusted component
366             setSettingViaShell(type, FAKE_SETTING_NAME_1,
367                     FAKE_SETTING_VALUE_2, false);
368 
369             // Reset the untrusted changes to defaults
370             resetSettingsViaShell(type,
371                     Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
372 
373             // Check whether only the untrusted changes set to defaults
374             assertEquals(FAKE_SETTING_VALUE_2, getSetting(type, FAKE_SETTING_NAME));
375             assertEquals(FAKE_SETTING_VALUE, getSetting(type, FAKE_SETTING_NAME_1));
376         } finally {
377             // Make sure we have a clean slate.
378             putSetting(type, FAKE_SETTING_NAME, null);
379             setSettingViaShell(type, FAKE_SETTING_NAME_1, null, true);
380         }
381     }
382 
383     // TODO(b/142206242): make this less flaky and re-enable it
384 //    @Test
385 //    public void testResetModeUntrustedClearGlobal() throws Exception {
386 //        testResetModeUntrustedClearCommon(SETTING_TYPE_GLOBAL);
387 //    }
388 
389     @Test
testResetModeUntrustedClearSecure()390     public void testResetModeUntrustedClearSecure() throws Exception {
391         testResetModeUntrustedClearCommon(SETTING_TYPE_SECURE);
392     }
393 
testResetModeUntrustedClearCommon(int type)394     private void testResetModeUntrustedClearCommon(int type) throws Exception {
395         // Make sure we have a clean slate.
396         putSetting(type, FAKE_SETTING_NAME, null);
397         setSettingViaShell(type, FAKE_SETTING_NAME_1, null, true);
398         try {
399             // Set a default setting as a trusted component
400             putSetting(type, FAKE_SETTING_NAME, FAKE_SETTING_VALUE);
401             // Change the setting as a trusted component
402             putSetting(type, FAKE_SETTING_NAME, FAKE_SETTING_VALUE_2);
403 
404             // Set a default setting as an untrusted component
405             setSettingViaShell(type, FAKE_SETTING_NAME_1,
406                     FAKE_SETTING_VALUE, true);
407             // Change the setting as an untrusted component
408             setSettingViaShell(type, FAKE_SETTING_NAME_1,
409                     FAKE_SETTING_VALUE_2, false);
410 
411             // Clear the untrusted changes
412             resetSettingsViaShell(type,
413                     Settings.RESET_MODE_UNTRUSTED_CHANGES);
414 
415             // Check whether only the untrusted changes set to defaults
416             assertEquals(FAKE_SETTING_VALUE_2, getSetting(type, FAKE_SETTING_NAME));
417             assertNull(getSetting(type, FAKE_SETTING_NAME_1));
418         } finally {
419             // Make sure we have a clean slate.
420             putSetting(type, FAKE_SETTING_NAME, null);
421             setSettingViaShell(type, FAKE_SETTING_NAME_1, null, true);
422         }
423     }
424 
425     // TODO(b/142206242): make this less flaky and re-enable it
426 //    @Test
427 //    public void testResetModeTrustedDefaultsGlobal() throws Exception {
428 //        testResetModeTrustedDefaultsCommon(SETTING_TYPE_GLOBAL);
429 //    }
430 
431     @Test
testResetModeTrustedDefaultsSecure()432     public void testResetModeTrustedDefaultsSecure() throws Exception {
433         testResetModeTrustedDefaultsCommon(SETTING_TYPE_SECURE);
434     }
435 
testResetModeTrustedDefaultsCommon(int type)436     private void testResetModeTrustedDefaultsCommon(int type) throws Exception {
437         // Make sure we have a clean slate.
438         putSetting(type, FAKE_SETTING_NAME, null);
439         setSettingViaShell(type, FAKE_SETTING_NAME_1, null, true);
440         try {
441             // Set a default setting as a trusted component
442             putSetting(type, FAKE_SETTING_NAME, FAKE_SETTING_VALUE);
443             // Change the setting as a trusted component
444             setSettingViaShell(type, FAKE_SETTING_NAME, FAKE_SETTING_VALUE_2, false);
445 
446             // Set a default setting as an untrusted component
447             setSettingViaShell(type, FAKE_SETTING_NAME_1,
448                     FAKE_SETTING_VALUE, true);
449             // Change the setting as an untrusted component
450             setSettingViaShell(type, FAKE_SETTING_NAME_1,
451                     FAKE_SETTING_VALUE_2, false);
452 
453             // Reset to trusted defaults
454             resetSettingsViaShell(type,
455                     Settings.RESET_MODE_TRUSTED_DEFAULTS);
456 
457             // Check whether snapped to trusted defaults
458             assertEquals(FAKE_SETTING_VALUE, getSetting(type, FAKE_SETTING_NAME));
459             assertNull(getSetting(type, FAKE_SETTING_NAME_1));
460         } finally {
461             // Make sure we have a clean slate.
462             putSetting(type, FAKE_SETTING_NAME, null);
463             setSettingViaShell(type, FAKE_SETTING_NAME_1, null, true);
464         }
465     }
466 
467     // To prevent FRP bypasses, the SECURE_FRP_MODE setting should not be reset when all other
468     // settings are reset.  But it should still be possible to explicitly set its value.
469     @Test
testSecureFrpModeSettingCannotBeReset()470     public void testSecureFrpModeSettingCannotBeReset() throws Exception {
471         final String name = Settings.Global.SECURE_FRP_MODE;
472         final String origValue = getSetting(SETTING_TYPE_GLOBAL, name);
473         setSettingViaShell(SETTING_TYPE_GLOBAL, name, "1", false);
474         try {
475             assertEquals("1", getSetting(SETTING_TYPE_GLOBAL, name));
476             for (int type : new int[] { SETTING_TYPE_GLOBAL, SETTING_TYPE_SECURE }) {
477                 resetSettingsViaShell(type, Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
478                 resetSettingsViaShell(type, Settings.RESET_MODE_UNTRUSTED_CHANGES);
479                 resetSettingsViaShell(type, Settings.RESET_MODE_TRUSTED_DEFAULTS);
480             }
481             // The value should still be "1".  It should not have been reset to null.
482             assertEquals("1", getSetting(SETTING_TYPE_GLOBAL, name));
483             // It should still be possible to explicitly set the value to "0".
484             setSettingViaShell(SETTING_TYPE_GLOBAL, name, "0", false);
485             assertEquals("0", getSetting(SETTING_TYPE_GLOBAL, name));
486         } finally {
487             setSettingViaShell(SETTING_TYPE_GLOBAL, name, origValue, false);
488             assertEquals(origValue, getSetting(SETTING_TYPE_GLOBAL, name));
489         }
490     }
491 
doTestQueryStringInBracketsViaProviderApiForType(int type)492     private void doTestQueryStringInBracketsViaProviderApiForType(int type) {
493         // Make sure we have a clean slate.
494         deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
495 
496         try {
497             // Insert the setting.
498             final Uri uri = insertStringViaProviderApi(type, FAKE_SETTING_NAME,
499                     FAKE_SETTING_VALUE, false);
500             Uri expectUri = Uri.withAppendedPath(getBaseUriForType(type), FAKE_SETTING_NAME);
501             assertEquals("Did not get expected Uri.", expectUri, uri);
502 
503             // Make sure the first setting is there.
504             String firstValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME, true, false);
505             assertEquals("Setting must be present", FAKE_SETTING_VALUE, firstValue);
506         } finally {
507             // Clean up.
508             deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
509         }
510     }
511 
toTestBulkInsertViaProviderApiForType(int type)512     private void toTestBulkInsertViaProviderApiForType(int type) {
513         // Make sure we have a clean slate.
514         deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
515         deleteStringViaProviderApi(type, FAKE_SETTING_NAME_1);
516         deleteStringViaProviderApi(type, FAKE_SETTING_NAME_2);
517 
518         try {
519             Uri uri = getBaseUriForType(type);
520             ContentValues[] allValues = new ContentValues[3];
521 
522             // Insert the first setting.
523             ContentValues firstValues = new ContentValues();
524             firstValues.put(Settings.NameValueTable.NAME, FAKE_SETTING_NAME);
525             firstValues.put(Settings.NameValueTable.VALUE, FAKE_SETTING_VALUE);
526             allValues[0] = firstValues;
527 
528             // Insert the second setting.
529             ContentValues secondValues = new ContentValues();
530             secondValues.put(Settings.NameValueTable.NAME, FAKE_SETTING_NAME_1);
531             secondValues.put(Settings.NameValueTable.VALUE, FAKE_SETTING_VALUE_1);
532             allValues[1] = secondValues;
533 
534             // Insert the third setting. (null)
535             ContentValues thirdValues = new ContentValues();
536             thirdValues.put(Settings.NameValueTable.NAME, FAKE_SETTING_NAME_2);
537             thirdValues.put(Settings.NameValueTable.VALUE, FAKE_SETTING_VALUE_2);
538             allValues[2] = thirdValues;
539 
540             // Verify insertion count.
541             final int insertCount = getContext().getContentResolver().bulkInsert(uri, allValues);
542             assertSame("Couldn't insert both values", 3, insertCount);
543 
544             // Make sure the first setting is there.
545             String firstValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
546             assertEquals("First setting must be present", FAKE_SETTING_VALUE, firstValue);
547 
548             // Make sure the second setting is there.
549             String secondValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME_1);
550             assertEquals("Second setting must be present", FAKE_SETTING_VALUE_1, secondValue);
551 
552             // Make sure the third setting is there.
553             String thirdValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME_2);
554             assertEquals("Third setting must be present", FAKE_SETTING_VALUE_2, thirdValue);
555         } finally {
556             // Clean up.
557             deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
558             deleteStringViaProviderApi(type, FAKE_SETTING_NAME_1);
559             deleteStringViaProviderApi(type, FAKE_SETTING_NAME_2);
560         }
561     }
562 
doTestQueryUpdateDeleteGlobalViaProviderApiForType(int type)563     private void doTestQueryUpdateDeleteGlobalViaProviderApiForType(int type) throws Exception {
564         // Make sure it is not there.
565         deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
566 
567         // Now selection should return nothing.
568         String value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
569         assertNull("Setting should not be present.", value);
570 
571         // Insert the setting.
572         Uri uri = insertStringViaProviderApi(type,
573                 FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
574         Uri expectUri = Uri.withAppendedPath(getBaseUriForType(type), FAKE_SETTING_NAME);
575         assertEquals("Did not get expected Uri.", expectUri, uri);
576 
577         // Now selection should return the setting.
578         value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
579         assertEquals("Setting should be present.", FAKE_SETTING_VALUE, value);
580 
581         // Update the setting.
582         final int changeCount = updateStringViaProviderApiSetting(type,
583                 FAKE_SETTING_NAME, FAKE_SETTING_VALUE_1);
584         assertEquals("Did not get expected change count.", 1, changeCount);
585 
586         // Now selection should return the new setting.
587         value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
588         assertEquals("Setting should be present.", FAKE_SETTING_VALUE_1, value);
589 
590         // Delete the setting.
591         final int deletedCount = deleteStringViaProviderApi(type,
592                 FAKE_SETTING_NAME);
593         assertEquals("Did not get expected deleted count", 1, deletedCount);
594 
595         // Now selection should return nothing.
596         value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
597         assertNull("Setting should not be present.", value);
598     }
599 
performSetAndGetSettingTestViaFrontEndApi(int type, int userId)600     private void performSetAndGetSettingTestViaFrontEndApi(int type, int userId)
601             throws Exception {
602         try {
603             // Change the setting and assert a successful change.
604             setSettingViaFrontEndApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME,
605                     FAKE_SETTING_VALUE, userId);
606         } finally {
607             // Remove the setting.
608             setStringViaFrontEndApiSetting(type, FAKE_SETTING_NAME, null, userId);
609         }
610     }
611 
performSetAndGetSettingTestViaProviderApi(int type)612     private void performSetAndGetSettingTestViaProviderApi(int type)
613             throws Exception {
614         try {
615             // Change the setting and assert a successful change.
616             setSettingViaProviderApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME,
617                     FAKE_SETTING_VALUE, true);
618         } finally {
619             // Remove the setting.
620             setSettingViaProviderApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME, null,
621                     true);
622         }
623     }
624 
setSettingViaFrontEndApiAndAssertSuccessfulChange(final int type, final String name, final String value, final int userId)625     private void setSettingViaFrontEndApiAndAssertSuccessfulChange(final int type,
626             final String name, final String value, final int userId) throws Exception {
627         setSettingAndAssertSuccessfulChange(() -> {
628             setStringViaFrontEndApiSetting(type, name, value, userId);
629         }, type, name, value, userId);
630     }
631 
setSettingViaProviderApiAndAssertSuccessfulChange(final int type, final String name, final String value, final boolean withTableRowUri)632     private void setSettingViaProviderApiAndAssertSuccessfulChange(final int type,
633             final String name, final String value, final boolean withTableRowUri)
634             throws Exception {
635         setSettingAndAssertSuccessfulChange(() -> {
636             insertStringViaProviderApi(type, name, value, withTableRowUri);
637         }, type, name, value, UserHandle.USER_SYSTEM);
638     }
639 
setSettingAndAssertSuccessfulChange(Runnable setCommand, final int type, final String name, final String value, final int userId)640     private void setSettingAndAssertSuccessfulChange(Runnable setCommand, final int type,
641             final String name, final String value, final int userId) throws Exception {
642         ContentResolver contentResolver = getContext().getContentResolver();
643 
644         final Uri settingUri = getBaseUriForType(type).buildUpon().appendPath(name).build();
645 
646         final AtomicBoolean success = new AtomicBoolean();
647 
648         ContentObserver contentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
649             public void onChange(boolean selfChange, Uri changeUri, int changeId) {
650                 Log.i(LOG_TAG, "onChange(" + selfChange + ", " + changeUri + ", " + changeId + ")");
651                 assertEquals("Wrong change Uri", changeUri, settingUri);
652                 assertEquals("Wrong user id", userId, changeId);
653                 String changeValue = getStringViaFrontEndApiSetting(type, name, userId);
654                 assertEquals("Wrong setting value", value, changeValue);
655 
656                 success.set(true);
657 
658                 synchronized (mLock) {
659                     mLock.notifyAll();
660                 }
661             }
662         };
663 
664         contentResolver.registerContentObserver(settingUri, false, contentObserver, userId);
665 
666         try {
667             setCommand.run();
668 
669             final long startTimeMillis = SystemClock.uptimeMillis();
670             synchronized (mLock) {
671                 while (true) {
672                     if (success.get()) {
673                         return;
674                     }
675                     final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
676                     if (elapsedTimeMillis >= WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS) {
677                         fail("Could not change setting for "
678                                 + WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS + " ms");
679                     }
680                     final long remainingTimeMillis = WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS
681                             - elapsedTimeMillis;
682                     try {
683                         mLock.wait(remainingTimeMillis);
684                     } catch (InterruptedException ie) {
685                         /* ignore */
686                     }
687                 }
688             }
689         } finally {
690             contentResolver.unregisterContentObserver(contentObserver);
691         }
692     }
693 
queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(int type, String name)694     private void queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(int type,
695             String name) {
696         Uri uri = getBaseUriForType(type);
697 
698         Cursor cursor = getContext().getContentResolver().query(uri, NAME_VALUE_COLUMNS,
699                 null, null, null);
700 
701         if (cursor == null || !cursor.moveToFirst()) {
702             fail("Nothing selected");
703         }
704 
705         try {
706             final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME);
707 
708             while (cursor.moveToNext()) {
709                 String currentName = cursor.getString(nameColumnIdx);
710                 if (name.equals(currentName)) {
711                     return;
712                 }
713             }
714 
715             fail("Not found setting: " + name);
716         } finally {
717             cursor.close();
718         }
719     }
720 }
721