1 /* 2 * Copyright (C) 2008 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 org.hamcrest.Matchers.aMapWithSize; 20 import static org.hamcrest.Matchers.greaterThanOrEqualTo; 21 import static org.junit.Assert.assertThat; 22 23 import android.content.ContentResolver; 24 import android.content.ContentUris; 25 import android.content.ContentValues; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.pm.PackageManager; 29 import android.content.pm.ResolveInfo; 30 import android.content.pm.UserInfo; 31 import android.database.Cursor; 32 import android.net.Uri; 33 import android.os.Bundle; 34 import android.os.UserHandle; 35 import android.os.UserManager; 36 import android.test.AndroidTestCase; 37 38 import androidx.test.filters.MediumTest; 39 import androidx.test.filters.SmallTest; 40 import androidx.test.filters.Suppress; 41 42 import java.util.HashMap; 43 import java.util.List; 44 import java.util.Map; 45 46 /** Unit test for SettingsProvider. */ 47 public class SettingsProviderTest extends AndroidTestCase { 48 49 @MediumTest testNameValueCache()50 public void testNameValueCache() { 51 ContentResolver r = getContext().getContentResolver(); 52 Settings.Secure.putString(r, "test_service", "Value"); 53 assertEquals("Value", Settings.Secure.getString(r, "test_service")); 54 55 // Make sure the value can be overwritten. 56 Settings.Secure.putString(r, "test_service", "New"); 57 assertEquals("New", Settings.Secure.getString(r, "test_service")); 58 59 // Also that delete works. 60 assertEquals(1, r.delete(Settings.Secure.getUriFor("test_service"), null, null)); 61 assertEquals(null, Settings.Secure.getString(r, "test_service")); 62 63 // Apps should not be able to use System settings. 64 try { 65 Settings.System.putString(r, "test_setting", "Value"); 66 fail("IllegalArgumentException expected"); 67 } catch (java.lang.IllegalArgumentException e) { 68 // expected 69 } 70 } 71 72 @MediumTest testRowNameContentUriForSecure()73 public void testRowNameContentUriForSecure() { 74 final String testKey = "testRowNameContentUriForSecure"; 75 final String testValue = "testValue"; 76 final String secondTestValue = "testValueNew"; 77 78 try { 79 testRowNameContentUri(Settings.Secure.CONTENT_URI, Settings.Secure.NAME, 80 Settings.Secure.VALUE, testKey, testValue, secondTestValue); 81 } finally { 82 // clean up 83 Settings.Secure.putString(getContext().getContentResolver(), testKey, null); 84 } 85 } 86 87 @MediumTest testRowNameContentUriForSystem()88 public void testRowNameContentUriForSystem() { 89 final String testKey = Settings.System.VIBRATE_ON; 90 assertTrue("Settings.System.PUBLIC_SETTINGS cannot be empty. We need to use one of it" 91 + " for testing. Only settings key in this collection will be accepted by the" 92 + " framework.", Settings.System.PUBLIC_SETTINGS.contains(testKey)); 93 final String testValue = "0"; 94 final String secondTestValue = "1"; 95 final String oldValue = 96 Settings.System.getString(getContext().getContentResolver(), testKey); 97 98 try { 99 testRowNameContentUri(Settings.System.CONTENT_URI, Settings.System.NAME, 100 Settings.System.VALUE, testKey, testValue, secondTestValue); 101 } finally { 102 // restore old value 103 if (oldValue != null) { 104 Settings.System.putString(getContext().getContentResolver(), testKey, oldValue); 105 } 106 } 107 } 108 testRowNameContentUri(Uri table, String nameField, String valueField, String testKey, String testValue, String secondTestValue)109 private void testRowNameContentUri(Uri table, String nameField, String valueField, 110 String testKey, String testValue, String secondTestValue) { 111 ContentResolver r = getContext().getContentResolver(); 112 113 ContentValues v = new ContentValues(); 114 v.put(nameField, testKey); 115 v.put(valueField, testValue); 116 117 r.insert(table, v); 118 Uri uri = Uri.parse(table.toString() + "/" + testKey); 119 120 // Query with a specific URI and no WHERE clause succeeds. 121 Cursor c = r.query(uri, null, null, null, null); 122 try { 123 assertTrue(c.moveToNext()); 124 assertEquals(testKey, c.getString(c.getColumnIndex(nameField))); 125 assertEquals(testValue, c.getString(c.getColumnIndex(valueField))); 126 assertFalse(c.moveToNext()); 127 } finally { 128 c.close(); 129 } 130 131 // Query with a specific URI and a WHERE clause fails. 132 try { 133 r.query(uri, null, "1", null, null); 134 fail("IllegalArgumentException expected"); 135 } catch (IllegalArgumentException e) { 136 // expected 137 } 138 139 // Query with a tablewide URI and a WHERE clause succeeds. 140 c = r.query(table, null, "name='" + testKey + "'", null, null); 141 try { 142 assertTrue(c.moveToNext()); 143 assertEquals(testKey, c.getString(c.getColumnIndex(nameField))); 144 assertEquals(testValue, c.getString(c.getColumnIndex(valueField))); 145 assertFalse(c.moveToNext()); 146 } finally { 147 c.close(); 148 } 149 150 v = new ContentValues(); 151 // NAME is still needed, although the uri should be specific enough. Why? 152 v.put(nameField, testKey); 153 v.put(valueField, secondTestValue); 154 assertEquals(1, r.update(uri, v, null, null)); 155 156 c = r.query(uri, null, null, null, null); 157 try { 158 assertTrue(c.moveToNext()); 159 assertEquals(testKey, c.getString(c.getColumnIndex(nameField))); 160 assertEquals(secondTestValue, c.getString(c.getColumnIndex(valueField))); 161 assertFalse(c.moveToNext()); 162 } finally { 163 c.close(); 164 } 165 } 166 167 @MediumTest testSettingsChangeForOtherUser()168 public void testSettingsChangeForOtherUser() { 169 UserManager um = (UserManager) getContext().getSystemService(Context.USER_SERVICE); 170 ContentResolver r = getContext().getContentResolver(); 171 172 // Make sure there's an owner 173 assertTrue(findUser(um, UserHandle.USER_SYSTEM)); 174 175 // create a new user to use for testing 176 UserInfo otherUser = um.createUser("TestUser1", UserInfo.FLAG_GUEST); 177 assertTrue(otherUser != null); 178 try { 179 assertNotSame("Current calling user id should not be the new guest user", 180 otherUser.id, UserHandle.getCallingUserId()); 181 182 final String testKey = "testSettingsChangeForOtherUser"; 183 final String testValue1 = "value1"; 184 final String testValue2 = "value2"; 185 Settings.Secure.putString(r, testKey, testValue1); 186 Settings.Secure.putStringForUser(r, testKey, testValue2, otherUser.id); 187 188 assertEquals(testValue1, Settings.Secure.getString(r, testKey)); 189 assertEquals(testValue2, Settings.Secure.getStringForUser(r, testKey, otherUser.id)); 190 191 assertNotSame("Current calling user id should not be the new guest user", 192 otherUser.id, UserHandle.getCallingUserId()); 193 } finally { 194 // Tidy up 195 um.removeUser(otherUser.id); 196 } 197 } 198 199 @MediumTest 200 @Suppress // Settings.Bookmarks uses a query format that's not supported now. testRowNumberContentUri()201 public void testRowNumberContentUri() { 202 ContentResolver r = getContext().getContentResolver(); 203 204 // The bookmarks table (and everything else) uses standard row number content URIs. 205 Uri uri = Settings.Bookmarks.add(r, new Intent("TEST"), 206 "Test Title", "Test Folder", '*', 123); 207 208 assertTrue(ContentUris.parseId(uri) > 0); 209 210 assertEquals("TEST", Settings.Bookmarks.getIntentForShortcut(r, '*').getAction()); 211 212 ContentValues v = new ContentValues(); 213 v.put(Settings.Bookmarks.INTENT, "#Intent;action=TOAST;end"); 214 assertEquals(1, r.update(uri, v, null, null)); 215 216 assertEquals("TOAST", Settings.Bookmarks.getIntentForShortcut(r, '*').getAction()); 217 218 assertEquals(1, r.delete(uri, null, null)); 219 220 assertEquals(null, Settings.Bookmarks.getIntentForShortcut(r, '*')); 221 } 222 223 @MediumTest testParseProviderList()224 public void testParseProviderList() { 225 ContentResolver r = getContext().getContentResolver(); 226 227 // We only accept "+value" and "-value" 228 // Test adding a value 229 Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "+test1"); 230 assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED) 231 .contains("test1")); 232 233 // Test adding a second value 234 Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "+test2"); 235 assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED) 236 .contains("test1")); 237 assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED) 238 .contains("test2")); 239 240 // Test adding a third value 241 Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "+test3"); 242 assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED) 243 .contains("test1")); 244 assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED) 245 .contains("test2")); 246 assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED) 247 .contains("test3")); 248 249 // Test deleting the first value in a 3 item list 250 Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "-test1"); 251 assertFalse(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED) 252 .contains("test1")); 253 254 // Test deleting the middle value in a 3 item list 255 Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "+test4"); 256 assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED) 257 .contains("test2")); 258 assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED) 259 .contains("test3")); 260 assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED) 261 .contains("test4")); 262 Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "-test3"); 263 assertFalse(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED) 264 .contains("test3")); 265 266 // Test deleting the last value in a 3 item list 267 Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "+test5"); 268 assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED) 269 .contains("test2")); 270 assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED) 271 .contains("test4")); 272 assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED) 273 .contains("test5")); 274 Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "-test5"); 275 assertFalse(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED) 276 .contains("test5")); 277 } 278 findUser(UserManager um, int userHandle)279 private boolean findUser(UserManager um, int userHandle) { 280 for (UserInfo user : um.getUsers()) { 281 if (user.id == userHandle) { 282 return true; 283 } 284 } 285 return false; 286 } 287 288 @MediumTest testPerUserSettings()289 public void testPerUserSettings() { 290 UserManager um = (UserManager) getContext().getSystemService(Context.USER_SERVICE); 291 ContentResolver r = getContext().getContentResolver(); 292 293 // Make sure there's an owner 294 assertTrue(findUser(um, UserHandle.USER_SYSTEM)); 295 296 // create a new user to use for testing 297 UserInfo user = um.createUser("TestUser1", UserInfo.FLAG_GUEST); 298 assertTrue(user != null); 299 300 try { 301 // Write some settings for that user as well as the current user 302 final String TEST_KEY = "test_setting"; 303 final int SELF_VALUE = 40; 304 final int OTHER_VALUE = 27; 305 306 Settings.Secure.putInt(r, TEST_KEY, SELF_VALUE); 307 Settings.Secure.putIntForUser(r, TEST_KEY, OTHER_VALUE, user.id); 308 309 // Verify that they read back as intended 310 int myValue = Settings.Secure.getInt(r, TEST_KEY, 0); 311 int otherValue = Settings.Secure.getIntForUser(r, TEST_KEY, 0, user.id); 312 assertTrue("Running as user " + UserHandle.myUserId() 313 + " and reading/writing as user " + user.id 314 + ", expected to read " + SELF_VALUE + " but got " + myValue, 315 myValue == SELF_VALUE); 316 assertTrue("Running as user " + UserHandle.myUserId() 317 + " and reading/writing as user " + user.id 318 + ", expected to read " + OTHER_VALUE + " but got " + otherValue, 319 otherValue == OTHER_VALUE); 320 } finally { 321 // Tidy up 322 um.removeUser(user.id); 323 } 324 } 325 326 @SmallTest testSettings()327 public void testSettings() { 328 assertCanBeHandled(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)); 329 assertCanBeHandled(new Intent(Settings.ACTION_ADD_ACCOUNT)); 330 assertCanBeHandled(new Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS)); 331 assertCanBeHandled(new Intent(Settings.ACTION_APN_SETTINGS)); 332 assertCanBeHandled(new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) 333 .setData(Uri.parse("package:" + getContext().getPackageName()))); 334 assertCanBeHandled(new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS)); 335 assertCanBeHandled(new Intent(Settings.ACTION_APPLICATION_SETTINGS)); 336 assertCanBeHandled(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS)); 337 assertCanBeHandled(new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS)); 338 assertCanBeHandled(new Intent(Settings.ACTION_DATE_SETTINGS)); 339 assertCanBeHandled(new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS)); 340 assertCanBeHandled(new Intent(Settings.ACTION_DISPLAY_SETTINGS)); 341 assertCanBeHandled(new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS)); 342 assertCanBeHandled(new Intent(Settings.ACTION_INTERNAL_STORAGE_SETTINGS)); 343 assertCanBeHandled(new Intent(Settings.ACTION_LOCALE_SETTINGS)); 344 assertCanBeHandled(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)); 345 assertCanBeHandled(new Intent(Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS)); 346 assertCanBeHandled(new Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS)); 347 assertCanBeHandled(new Intent(Settings.ACTION_MEMORY_CARD_SETTINGS)); 348 assertCanBeHandled(new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS)); 349 assertCanBeHandled(new Intent(Settings.ACTION_PRIVACY_SETTINGS)); 350 //TODO: seems no one is using this anymore. 351 // assertCanBeHandled(new Intent(Settings.ACTION_QUICK_LAUNCH_SETTINGS)); 352 assertCanBeHandled(new Intent(Settings.ACTION_SEARCH_SETTINGS)); 353 assertCanBeHandled(new Intent(Settings.ACTION_SECURITY_SETTINGS)); 354 assertCanBeHandled(new Intent(Settings.ACTION_SETTINGS)); 355 assertCanBeHandled(new Intent(Settings.ACTION_SOUND_SETTINGS)); 356 assertCanBeHandled(new Intent(Settings.ACTION_SYNC_SETTINGS)); 357 assertCanBeHandled(new Intent(Settings.ACTION_SYSTEM_UPDATE_SETTINGS)); 358 assertCanBeHandled(new Intent(Settings.ACTION_USER_DICTIONARY_SETTINGS)); 359 assertCanBeHandled(new Intent(Settings.ACTION_WIFI_IP_SETTINGS)); 360 assertCanBeHandled(new Intent(Settings.ACTION_WIFI_SETTINGS)); 361 assertCanBeHandled(new Intent(Settings.ACTION_WIRELESS_SETTINGS)); 362 363 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) { 364 assertCanBeHandled(new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS)); 365 } 366 } 367 assertCanBeHandled(final Intent intent)368 private void assertCanBeHandled(final Intent intent) { 369 PackageManager packageManager = mContext.getPackageManager(); 370 List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, 0); 371 assertNotNull(resolveInfoList); 372 // one or more activity can handle this intent. 373 assertTrue(resolveInfoList.size() > 0); 374 } 375 376 @SmallTest testValidSsaid()377 public void testValidSsaid() { 378 ContentResolver r = getContext().getContentResolver(); 379 380 // Verify ssaid 381 String ssaid = Settings.Secure.getString(r, Settings.Secure.ANDROID_ID); 382 assertTrue(ssaid != null); 383 assertTrue(ssaid.length() == 16); 384 385 String ssaid2 = Settings.Secure.getString(r, Settings.Secure.ANDROID_ID); 386 assertTrue(ssaid2 != null); 387 assertTrue(ssaid2.length() == 16); 388 389 assertTrue(ssaid.equals(ssaid2)); 390 } 391 392 @MediumTest testCall_putAndGetConfig()393 public void testCall_putAndGetConfig() { 394 ContentResolver r = getContext().getContentResolver(); 395 String name = "key1"; 396 String value = "value1"; 397 String newValue = "value2"; 398 Bundle args = new Bundle(); 399 args.putString(Settings.NameValueTable.VALUE, value); 400 401 try { 402 // value is empty 403 Bundle results = 404 r.call(DeviceConfig.CONTENT_URI, Settings.CALL_METHOD_GET_CONFIG, name, null); 405 assertNull(results.get(Settings.NameValueTable.VALUE)); 406 407 // save value 408 results = r.call(DeviceConfig.CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, name, args); 409 assertNull(results); 410 411 // value is no longer empty 412 results = r.call(DeviceConfig.CONTENT_URI, Settings.CALL_METHOD_GET_CONFIG, name, null); 413 assertEquals(value, results.get(Settings.NameValueTable.VALUE)); 414 415 // save new value 416 args.putString(Settings.NameValueTable.VALUE, newValue); 417 r.call(DeviceConfig.CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, name, args); 418 419 // new value is returned 420 results = r.call(DeviceConfig.CONTENT_URI, Settings.CALL_METHOD_GET_CONFIG, name, null); 421 assertEquals(newValue, results.get(Settings.NameValueTable.VALUE)); 422 } finally { 423 // clean up 424 r.call(DeviceConfig.CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, name, null); 425 } 426 } 427 428 @MediumTest testCall_deleteConfig()429 public void testCall_deleteConfig() { 430 ContentResolver r = getContext().getContentResolver(); 431 String name = "key1"; 432 String value = "value1"; 433 Bundle args = new Bundle(); 434 args.putString(Settings.NameValueTable.VALUE, value); 435 436 try { 437 // save value 438 r.call(DeviceConfig.CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, name, args); 439 440 // get value 441 Bundle results = 442 r.call(DeviceConfig.CONTENT_URI, Settings.CALL_METHOD_GET_CONFIG, name, null); 443 assertEquals(value, results.get(Settings.NameValueTable.VALUE)); 444 445 // delete value 446 results = r.call(DeviceConfig.CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, name, 447 null); 448 449 // value is empty now 450 results = r.call(DeviceConfig.CONTENT_URI, Settings.CALL_METHOD_GET_CONFIG, name, null); 451 assertNull(results.get(Settings.NameValueTable.VALUE)); 452 } finally { 453 // clean up 454 r.call(DeviceConfig.CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, name, null); 455 } 456 } 457 458 @MediumTest testCall_listConfig()459 public void testCall_listConfig() { 460 ContentResolver r = getContext().getContentResolver(); 461 String prefix = "foo"; 462 String newPrefix = "bar"; 463 String name = prefix + "/" + "key1"; 464 String newName = newPrefix + "/" + "key1"; 465 String value = "value1"; 466 String newValue = "value2"; 467 Bundle args = new Bundle(); 468 args.putString(Settings.NameValueTable.VALUE, value); 469 470 try { 471 // save both values 472 r.call(DeviceConfig.CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, name, args); 473 args.putString(Settings.NameValueTable.VALUE, newValue); 474 r.call(DeviceConfig.CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, newName, args); 475 476 // list all values 477 Bundle result = r.call(DeviceConfig.CONTENT_URI, Settings.CALL_METHOD_LIST_CONFIG, 478 null, null); 479 Map<String, String> keyValueMap = 480 (HashMap) result.getSerializable(Settings.NameValueTable.VALUE); 481 assertThat(keyValueMap.size(), greaterThanOrEqualTo(2)); 482 assertEquals(value, keyValueMap.get(name)); 483 assertEquals(newValue, keyValueMap.get(newName)); 484 485 // list values for prefix 486 args.putString(Settings.CALL_METHOD_PREFIX_KEY, prefix); 487 result = r.call(DeviceConfig.CONTENT_URI, Settings.CALL_METHOD_LIST_CONFIG, null, args); 488 keyValueMap = (HashMap) result.getSerializable(Settings.NameValueTable.VALUE); 489 assertThat(keyValueMap, aMapWithSize(1)); 490 assertEquals(value, keyValueMap.get(name)); 491 } finally { 492 // clean up 493 r.call(DeviceConfig.CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, name, null); 494 r.call(DeviceConfig.CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, newName, null); 495 } 496 } 497 } 498