Home | History | Annotate | Download | only in settings
      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 android.content.ContentResolver;
     20 import android.content.ContentValues;
     21 import android.database.ContentObserver;
     22 import android.database.Cursor;
     23 import android.net.Uri;
     24 import android.os.Handler;
     25 import android.os.Looper;
     26 import android.os.SystemClock;
     27 import android.os.UserHandle;
     28 import android.provider.Settings;
     29 import android.util.Log;
     30 
     31 import java.util.concurrent.atomic.AtomicBoolean;
     32 
     33 /**
     34  * Tests for the SettingContentProvider.
     35  *
     36  * Before you run this test you must add a secondary user.
     37  */
     38 public class SettingsProviderTest extends BaseSettingsProviderTest {
     39     private static final String LOG_TAG = "SettingsProviderTest";
     40 
     41     private static final long WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS = 2000; // 2 sec
     42 
     43     private static final String[] NAME_VALUE_COLUMNS = new String[]{
     44             Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE
     45     };
     46 
     47     private final Object mLock = new Object();
     48 
     49     public void testSetAndGetGlobalViaFrontEndApiForSystemUser() throws Exception {
     50         performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
     51     }
     52 
     53     public void testSetAndGetGlobalViaFrontEndApiForNonSystemUser() throws Exception {
     54         if (mSecondaryUserId == UserHandle.USER_SYSTEM) {
     55             Log.w(LOG_TAG, "No secondary user. Skipping "
     56                     + "testSetAndGetGlobalViaFrontEndApiForNonSystemUser");
     57             return;
     58         }
     59         performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, mSecondaryUserId);
     60     }
     61 
     62     public void testSetAndGetSecureViaFrontEndApiForSystemUser() throws Exception {
     63         performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, UserHandle.USER_SYSTEM);
     64     }
     65 
     66     public void testSetAndGetSecureViaFrontEndApiForNonSystemUser() throws Exception {
     67         if (mSecondaryUserId == UserHandle.USER_SYSTEM) {
     68             Log.w(LOG_TAG, "No secondary user. Skipping "
     69                     + "testSetAndGetSecureViaFrontEndApiForNonSystemUser");
     70             return;
     71         }
     72         performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, mSecondaryUserId);
     73     }
     74 
     75     public void testSetAndGetSystemViaFrontEndApiForSystemUser() throws Exception {
     76         performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, UserHandle.USER_SYSTEM);
     77     }
     78 
     79     public void testSetAndGetSystemViaFrontEndApiForNonSystemUser() throws Exception {
     80         if (mSecondaryUserId == UserHandle.USER_SYSTEM) {
     81             Log.w(LOG_TAG, "No secondary user. Skipping "
     82                     + "testSetAndGetSystemViaFrontEndApiForNonSystemUser");
     83             return;
     84         }
     85         performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, mSecondaryUserId);
     86     }
     87 
     88     public void testSetAndGetGlobalViaProviderApi() throws Exception {
     89         performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_GLOBAL);
     90     }
     91 
     92     public void testSetAndGetSecureViaProviderApi() throws Exception {
     93         performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_SECURE);
     94     }
     95 
     96     public void testSetAndGetSystemViaProviderApi() throws Exception {
     97         performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_SYSTEM);
     98     }
     99 
    100     public void testSelectAllGlobalViaProviderApi() throws Exception {
    101         setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_GLOBAL,
    102                 FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
    103         try {
    104             queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_GLOBAL,
    105                     FAKE_SETTING_NAME);
    106         } finally {
    107             deleteStringViaProviderApi(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME);
    108         }
    109     }
    110 
    111     public void testSelectAllSecureViaProviderApi() throws Exception {
    112         setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_SECURE,
    113                 FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
    114         try {
    115             queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_SECURE,
    116                     FAKE_SETTING_NAME);
    117         } finally {
    118             deleteStringViaProviderApi(SETTING_TYPE_SECURE, FAKE_SETTING_NAME);
    119         }
    120     }
    121 
    122     public void testSelectAllSystemViaProviderApi() throws Exception {
    123         setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_SYSTEM,
    124                 FAKE_SETTING_NAME, FAKE_SETTING_VALUE, true);
    125         try {
    126             queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_SYSTEM,
    127                     FAKE_SETTING_NAME);
    128         } finally {
    129             deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME);
    130         }
    131     }
    132 
    133     public void testQueryUpdateDeleteGlobalViaProviderApi() throws Exception {
    134         doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_GLOBAL);
    135     }
    136 
    137     public void testQueryUpdateDeleteSecureViaProviderApi() throws Exception {
    138         doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_SECURE);
    139     }
    140 
    141     public void testQueryUpdateDeleteSystemViaProviderApi() throws Exception {
    142         doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_SYSTEM);
    143     }
    144 
    145     public void testBulkInsertGlobalViaProviderApi() throws Exception {
    146         toTestBulkInsertViaProviderApiForType(SETTING_TYPE_GLOBAL);
    147     }
    148 
    149     public void testBulkInsertSystemViaProviderApi() throws Exception {
    150         toTestBulkInsertViaProviderApiForType(SETTING_TYPE_SYSTEM);
    151     }
    152 
    153     public void testBulkInsertSecureViaProviderApi() throws Exception {
    154         toTestBulkInsertViaProviderApiForType(SETTING_TYPE_SECURE);
    155     }
    156 
    157     public void testAppCannotRunsSystemOutOfMemoryWritingSystemSettings() throws Exception {
    158         int insertedCount = 0;
    159         try {
    160             for (; insertedCount < 1200; insertedCount++) {
    161                 Log.w(LOG_TAG, "Adding app specific setting: " + insertedCount);
    162                 insertStringViaProviderApi(SETTING_TYPE_SYSTEM,
    163                         String.valueOf(insertedCount), FAKE_SETTING_VALUE, false);
    164             }
    165             fail("Adding app specific settings must be bound.");
    166         } catch (Exception e) {
    167             for (; insertedCount >= 0; insertedCount--) {
    168                 Log.w(LOG_TAG, "Removing app specific setting: " + insertedCount);
    169                 deleteStringViaProviderApi(SETTING_TYPE_SYSTEM,
    170                         String.valueOf(insertedCount));
    171             }
    172         }
    173     }
    174 
    175     public void testQueryStringInBracketsGlobalViaProviderApiForType() throws Exception {
    176         doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_GLOBAL);
    177     }
    178 
    179     public void testQueryStringInBracketsSecureViaProviderApiForType() throws Exception {
    180         doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_SECURE);
    181     }
    182 
    183     public void testQueryStringInBracketsSystemViaProviderApiForType() throws Exception {
    184         doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_SYSTEM);
    185     }
    186 
    187     public void testQueryStringWithAppendedNameToUriViaProviderApi() throws Exception {
    188         // Make sure we have a clean slate.
    189         deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME);
    190 
    191         try {
    192             // Insert the setting.
    193             final Uri uri = insertStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME,
    194                     FAKE_SETTING_VALUE, false);
    195             Uri expectUri = Uri.withAppendedPath(getBaseUriForType(SETTING_TYPE_SYSTEM),
    196                     FAKE_SETTING_NAME);
    197             assertEquals("Did not get expected Uri.", expectUri, uri);
    198 
    199             // Make sure the first setting is there.
    200             String firstValue = queryStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME,
    201                     false, true);
    202             assertEquals("Setting must be present", FAKE_SETTING_VALUE, firstValue);
    203         } finally {
    204             // Clean up.
    205             deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME);
    206         }
    207     }
    208 
    209     private void doTestQueryStringInBracketsViaProviderApiForType(int type) {
    210         // Make sure we have a clean slate.
    211         deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
    212 
    213         try {
    214             // Insert the setting.
    215             final Uri uri = insertStringViaProviderApi(type, FAKE_SETTING_NAME,
    216                     FAKE_SETTING_VALUE, false);
    217             Uri expectUri = Uri.withAppendedPath(getBaseUriForType(type), FAKE_SETTING_NAME);
    218             assertEquals("Did not get expected Uri.", expectUri, uri);
    219 
    220             // Make sure the first setting is there.
    221             String firstValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME, true, false);
    222             assertEquals("Setting must be present", FAKE_SETTING_VALUE, firstValue);
    223         } finally {
    224             // Clean up.
    225             deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
    226         }
    227     }
    228 
    229     private void toTestBulkInsertViaProviderApiForType(int type) {
    230         // Make sure we have a clean slate.
    231         deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
    232         deleteStringViaProviderApi(type, FAKE_SETTING_NAME_1);
    233         deleteStringViaProviderApi(type, FAKE_SETTING_NAME_2);
    234 
    235         try {
    236             Uri uri = getBaseUriForType(type);
    237             ContentValues[] allValues = new ContentValues[3];
    238 
    239             // Insert the first setting.
    240             ContentValues firstValues = new ContentValues();
    241             firstValues.put(Settings.NameValueTable.NAME, FAKE_SETTING_NAME);
    242             firstValues.put(Settings.NameValueTable.VALUE, FAKE_SETTING_VALUE);
    243             allValues[0] = firstValues;
    244 
    245             // Insert the second setting.
    246             ContentValues secondValues = new ContentValues();
    247             secondValues.put(Settings.NameValueTable.NAME, FAKE_SETTING_NAME_1);
    248             secondValues.put(Settings.NameValueTable.VALUE, FAKE_SETTING_VALUE_1);
    249             allValues[1] = secondValues;
    250 
    251             // Insert the third setting. (null)
    252             ContentValues thirdValues = new ContentValues();
    253             thirdValues.put(Settings.NameValueTable.NAME, FAKE_SETTING_NAME_2);
    254             thirdValues.put(Settings.NameValueTable.VALUE, FAKE_SETTING_VALUE_2);
    255             allValues[2] = thirdValues;
    256 
    257             // Verify insertion count.
    258             final int insertCount = getContext().getContentResolver().bulkInsert(uri, allValues);
    259             assertSame("Couldn't insert both values", 3, insertCount);
    260 
    261             // Make sure the first setting is there.
    262             String firstValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
    263             assertEquals("First setting must be present", FAKE_SETTING_VALUE, firstValue);
    264 
    265             // Make sure the second setting is there.
    266             String secondValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME_1);
    267             assertEquals("Second setting must be present", FAKE_SETTING_VALUE_1, secondValue);
    268 
    269             // Make sure the third setting is there.
    270             String thirdValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME_2);
    271             assertEquals("Third setting must be present", FAKE_SETTING_VALUE_2, thirdValue);
    272         } finally {
    273             // Clean up.
    274             deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
    275             deleteStringViaProviderApi(type, FAKE_SETTING_NAME_1);
    276             deleteStringViaProviderApi(type, FAKE_SETTING_NAME_2);
    277         }
    278     }
    279 
    280     private void doTestQueryUpdateDeleteGlobalViaProviderApiForType(int type) throws Exception {
    281         // Make sure it is not there.
    282         deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
    283 
    284         // Now selection should return nothing.
    285         String value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
    286         assertNull("Setting should not be present.", value);
    287 
    288         // Insert the setting.
    289         Uri uri = insertStringViaProviderApi(type,
    290                 FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
    291         Uri expectUri = Uri.withAppendedPath(getBaseUriForType(type), FAKE_SETTING_NAME);
    292         assertEquals("Did not get expected Uri.", expectUri, uri);
    293 
    294         // Now selection should return the setting.
    295         value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
    296         assertEquals("Setting should be present.", FAKE_SETTING_VALUE, value);
    297 
    298         // Update the setting.
    299         final int changeCount = updateStringViaProviderApiSetting(type,
    300                 FAKE_SETTING_NAME, FAKE_SETTING_VALUE_1);
    301         assertEquals("Did not get expected change count.", 1, changeCount);
    302 
    303         // Now selection should return the new setting.
    304         value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
    305         assertEquals("Setting should be present.", FAKE_SETTING_VALUE_1, value);
    306 
    307         // Delete the setting.
    308         final int deletedCount = deleteStringViaProviderApi(type,
    309                 FAKE_SETTING_NAME);
    310         assertEquals("Did not get expected deleted count", 1, deletedCount);
    311 
    312         // Now selection should return nothing.
    313         value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
    314         assertNull("Setting should not be present.", value);
    315     }
    316 
    317     private void performSetAndGetSettingTestViaFrontEndApi(int type, int userId)
    318             throws Exception {
    319         try {
    320             // Change the setting and assert a successful change.
    321             setSettingViaFrontEndApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME,
    322                     FAKE_SETTING_VALUE, userId);
    323         } finally {
    324             // Remove the setting.
    325             setStringViaFrontEndApiSetting(type, FAKE_SETTING_NAME, null, userId);
    326         }
    327     }
    328 
    329     private void performSetAndGetSettingTestViaProviderApi(int type)
    330             throws Exception {
    331         try {
    332             // Change the setting and assert a successful change.
    333             setSettingViaProviderApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME,
    334                     FAKE_SETTING_VALUE, true);
    335         } finally {
    336             // Remove the setting.
    337             setSettingViaProviderApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME, null,
    338                     true);
    339         }
    340     }
    341 
    342     private void setSettingViaFrontEndApiAndAssertSuccessfulChange(final int type,
    343             final String name, final String value, final int userId) throws Exception {
    344         setSettingAndAssertSuccessfulChange(new Runnable() {
    345             @Override
    346             public void run() {
    347                 setStringViaFrontEndApiSetting(type, name, value, userId);
    348             }
    349         }, type, name, value, userId);
    350     }
    351 
    352     private void setSettingViaProviderApiAndAssertSuccessfulChange(final int type,
    353             final String name, final String value, final boolean withTableRowUri)
    354             throws Exception {
    355         setSettingAndAssertSuccessfulChange(new Runnable() {
    356             @Override
    357             public void run() {
    358                 insertStringViaProviderApi(type, name, value, withTableRowUri);
    359             }
    360         }, type, name, value, UserHandle.USER_SYSTEM);
    361     }
    362 
    363     private void setSettingAndAssertSuccessfulChange(Runnable setCommand, final int type,
    364             final String name, final String value, final int userId) throws Exception {
    365         ContentResolver contentResolver = getContext().getContentResolver();
    366 
    367         final Uri settingUri = getBaseUriForType(type);
    368 
    369         final AtomicBoolean success = new AtomicBoolean();
    370 
    371         ContentObserver contentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
    372             public void onChange(boolean selfChange, Uri changeUri, int changeId) {
    373                 Log.i(LOG_TAG, "onChange(" + selfChange + ", " + changeUri + ", " + changeId + ")");
    374                 assertEquals("Wrong change Uri", changeUri, settingUri);
    375                 assertEquals("Wrong user id", userId, changeId);
    376                 String changeValue = getStringViaFrontEndApiSetting(type, name, userId);
    377                 assertEquals("Wrong setting value", value, changeValue);
    378 
    379                 success.set(true);
    380 
    381                 synchronized (mLock) {
    382                     mLock.notifyAll();
    383                 }
    384             }
    385         };
    386 
    387         contentResolver.registerContentObserver(settingUri, false, contentObserver, userId);
    388 
    389         try {
    390             setCommand.run();
    391 
    392             final long startTimeMillis = SystemClock.uptimeMillis();
    393             synchronized (mLock) {
    394                 if (success.get()) {
    395                     return;
    396                 }
    397                 final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
    398                 if (elapsedTimeMillis > WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS) {
    399                     fail("Could not change setting for "
    400                             + WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS + " ms");
    401                 }
    402                 final long remainingTimeMillis = WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS
    403                         - elapsedTimeMillis;
    404                 try {
    405                     mLock.wait(remainingTimeMillis);
    406                 } catch (InterruptedException ie) {
    407                     /* ignore */
    408                 }
    409             }
    410         } finally {
    411             contentResolver.unregisterContentObserver(contentObserver);
    412         }
    413     }
    414 
    415     private void queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(int type,
    416             String name) {
    417         Uri uri = getBaseUriForType(type);
    418 
    419         Cursor cursor = getContext().getContentResolver().query(uri, NAME_VALUE_COLUMNS,
    420                 null, null, null);
    421 
    422         if (cursor == null || !cursor.moveToFirst()) {
    423             fail("Nothing selected");
    424         }
    425 
    426         try {
    427             final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME);
    428 
    429             while (cursor.moveToNext()) {
    430                 String currentName = cursor.getString(nameColumnIdx);
    431                 if (name.equals(currentName)) {
    432                     return;
    433                 }
    434             }
    435 
    436             fail("Not found setting: " + name);
    437         } finally {
    438             cursor.close();
    439         }
    440     }
    441 }
    442