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.content.Context; 22 import android.content.pm.UserInfo; 23 import android.database.Cursor; 24 import android.net.Uri; 25 import android.os.UserHandle; 26 import android.os.UserManager; 27 import android.provider.Settings; 28 29 import androidx.test.InstrumentationRegistry; 30 import androidx.test.runner.AndroidJUnit4; 31 32 import libcore.io.Streams; 33 34 import org.junit.runner.RunWith; 35 36 import java.io.FileInputStream; 37 import java.io.IOException; 38 import java.io.InputStream; 39 import java.util.List; 40 41 /** 42 * Base class for the SettingContentProvider tests. 43 */ 44 @RunWith(AndroidJUnit4.class) 45 abstract class BaseSettingsProviderTest { 46 protected static final int SETTING_TYPE_GLOBAL = 1; 47 protected static final int SETTING_TYPE_SECURE = 2; 48 protected static final int SETTING_TYPE_SYSTEM = 3; 49 50 protected static final String FAKE_SETTING_NAME = "fake_setting_name"; 51 protected static final String FAKE_SETTING_NAME_1 = "fake_setting_name1"; 52 protected static final String FAKE_SETTING_NAME_2 = "fake_setting_name2"; 53 protected static final String FAKE_SETTING_VALUE = "fake_setting_value"; 54 protected static final String FAKE_SETTING_VALUE_1 = SettingsStateTest.CRAZY_STRING; 55 protected static final String FAKE_SETTING_VALUE_2 = null; 56 57 private static final String[] NAME_VALUE_COLUMNS = new String[] { 58 Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE 59 }; 60 61 private int mSecondaryUserId = Integer.MIN_VALUE; 62 setStringViaFrontEndApiSetting(int type, String name, String value, int userId)63 protected void setStringViaFrontEndApiSetting(int type, String name, String value, int userId) { 64 ContentResolver contentResolver = getContext().getContentResolver(); 65 66 switch (type) { 67 case SETTING_TYPE_GLOBAL: { 68 Settings.Global.putStringForUser(contentResolver, name, value, userId); 69 } break; 70 71 case SETTING_TYPE_SECURE: { 72 Settings.Secure.putStringForUser(contentResolver, name, value, userId); 73 } break; 74 75 case SETTING_TYPE_SYSTEM: { 76 Settings.System.putStringForUser(contentResolver, name, value, userId); 77 } break; 78 79 default: { 80 throw new IllegalArgumentException("Invalid type: " + type); 81 } 82 } 83 } 84 getStringViaFrontEndApiSetting(int type, String name, int userId)85 protected String getStringViaFrontEndApiSetting(int type, String name, int userId) { 86 ContentResolver contentResolver = getContext().getContentResolver(); 87 88 switch (type) { 89 case SETTING_TYPE_GLOBAL: { 90 return Settings.Global.getStringForUser(contentResolver, name, userId); 91 } 92 93 case SETTING_TYPE_SECURE: { 94 return Settings.Secure.getStringForUser(contentResolver, name, userId); 95 } 96 97 case SETTING_TYPE_SYSTEM: { 98 return Settings.System.getStringForUser(contentResolver, name, userId); 99 } 100 101 default: { 102 throw new IllegalArgumentException("Invalid type: " + type); 103 } 104 } 105 } 106 insertStringViaProviderApi(int type, String name, String value, boolean withTableRowUri)107 protected Uri insertStringViaProviderApi(int type, String name, String value, 108 boolean withTableRowUri) { 109 Uri uri = getBaseUriForType(type); 110 if (withTableRowUri) { 111 uri = Uri.withAppendedPath(uri, name); 112 } 113 ContentValues values = new ContentValues(); 114 values.put(Settings.NameValueTable.NAME, name); 115 values.put(Settings.NameValueTable.VALUE, value); 116 117 return getContext().getContentResolver().insert(uri, values); 118 } 119 deleteStringViaProviderApi(int type, String name)120 protected int deleteStringViaProviderApi(int type, String name) { 121 Uri uri = getBaseUriForType(type); 122 return getContext().getContentResolver().delete(uri, "name=?", new String[]{name}); 123 } 124 updateStringViaProviderApiSetting(int type, String name, String value)125 protected int updateStringViaProviderApiSetting(int type, String name, String value) { 126 Uri uri = getBaseUriForType(type); 127 ContentValues values = new ContentValues(); 128 values.put(Settings.NameValueTable.NAME, name); 129 values.put(Settings.NameValueTable.VALUE, value); 130 return getContext().getContentResolver().update(uri, values, "name=?", 131 new String[]{name}); 132 } 133 queryStringViaProviderApi(int type, String name)134 protected String queryStringViaProviderApi(int type, String name) { 135 return queryStringViaProviderApi(type, name, false, false); 136 } 137 queryStringViaProviderApi(int type, String name, boolean queryStringInQuotes, boolean appendNameToUri)138 protected String queryStringViaProviderApi(int type, String name, boolean queryStringInQuotes, 139 boolean appendNameToUri) { 140 final Uri uri; 141 final String queryString; 142 final String[] queryArgs; 143 144 if (appendNameToUri) { 145 uri = Uri.withAppendedPath(getBaseUriForType(type), name); 146 queryString = null; 147 queryArgs = null; 148 } else { 149 uri = getBaseUriForType(type); 150 queryString = queryStringInQuotes ? "(name=?)" : "name=?"; 151 queryArgs = new String[]{name}; 152 } 153 154 Cursor cursor = getContext().getContentResolver().query(uri, NAME_VALUE_COLUMNS, 155 queryString, queryArgs, null); 156 157 if (cursor == null) { 158 return null; 159 } 160 161 try { 162 if (cursor.moveToFirst()) { 163 final int valueColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.VALUE); 164 return cursor.getString(valueColumnIdx); 165 } 166 } finally { 167 cursor.close(); 168 } 169 170 return null; 171 } 172 resetSettingsViaShell(int type, int resetMode)173 protected static void resetSettingsViaShell(int type, int resetMode) throws IOException { 174 final String modeString; 175 switch (resetMode) { 176 case Settings.RESET_MODE_UNTRUSTED_DEFAULTS: { 177 modeString = "untrusted_defaults"; 178 } break; 179 180 case Settings.RESET_MODE_UNTRUSTED_CHANGES: { 181 modeString = "untrusted_clear"; 182 } break; 183 184 case Settings.RESET_MODE_TRUSTED_DEFAULTS: { 185 modeString = "trusted_defaults"; 186 } break; 187 188 default: { 189 throw new IllegalArgumentException("Invalid reset mode: " + resetMode); 190 } 191 } 192 193 switch (type) { 194 case SETTING_TYPE_GLOBAL: { 195 executeShellCommand("settings reset global " + modeString); 196 } break; 197 198 case SETTING_TYPE_SECURE: { 199 executeShellCommand("settings reset secure " + modeString); 200 } break; 201 202 default: { 203 throw new IllegalArgumentException("Invalid type: " + type); 204 } 205 } 206 } 207 resetToDefaultsViaShell(int type, String packageName)208 protected static void resetToDefaultsViaShell(int type, String packageName) throws IOException { 209 resetToDefaultsViaShell(type, packageName, null); 210 } 211 resetToDefaultsViaShell(int type, String packageName, String tag)212 protected static void resetToDefaultsViaShell(int type, String packageName, String tag) 213 throws IOException { 214 switch (type) { 215 case SETTING_TYPE_GLOBAL: { 216 executeShellCommand("settings reset global " + packageName + " " 217 + (tag != null ? tag : "")); 218 } break; 219 220 case SETTING_TYPE_SECURE: { 221 executeShellCommand("settings reset secure " + packageName + " " 222 + (tag != null ? tag : "")); 223 } break; 224 225 case SETTING_TYPE_SYSTEM: { 226 executeShellCommand("settings reset system " + packageName + " " 227 + (tag != null ? tag : "")); 228 } break; 229 230 default: { 231 throw new IllegalArgumentException("Invalid type: " + type); 232 } 233 } 234 } 235 getSetting(int type, String name)236 protected String getSetting(int type, String name) { 237 switch (type) { 238 case SETTING_TYPE_GLOBAL: { 239 return Settings.Global.getString(getContext().getContentResolver(), name); 240 } 241 242 case SETTING_TYPE_SECURE: { 243 return Settings.Secure.getString(getContext().getContentResolver(), name); 244 } 245 246 case SETTING_TYPE_SYSTEM: { 247 return Settings.System.getString(getContext().getContentResolver(), name); 248 } 249 250 default: { 251 throw new IllegalArgumentException("Invalid type: " + type); 252 } 253 } 254 } 255 putSetting(int type, String name, String value)256 protected void putSetting(int type, String name, String value) { 257 switch (type) { 258 case SETTING_TYPE_GLOBAL: { 259 Settings.Global.putString(getContext().getContentResolver(), name, value); 260 } break; 261 262 case SETTING_TYPE_SECURE: { 263 Settings.Secure.putString(getContext().getContentResolver(), name, value); 264 } break; 265 266 case SETTING_TYPE_SYSTEM: { 267 Settings.System.putString(getContext().getContentResolver(), name, value); 268 } break; 269 270 default: { 271 throw new IllegalArgumentException("Invalid type: " + type); 272 } 273 } 274 } 275 setSettingViaShell(int type, String name, String value, boolean makeDefault)276 protected static void setSettingViaShell(int type, String name, String value, 277 boolean makeDefault) throws IOException { 278 setSettingViaShell(type, name, value, null, makeDefault); 279 } 280 setSettingViaShell(int type, String name, String value, String token, boolean makeDefault)281 protected static void setSettingViaShell(int type, String name, String value, 282 String token, boolean makeDefault) throws IOException { 283 switch (type) { 284 case SETTING_TYPE_GLOBAL: { 285 executeShellCommand("settings put global " + name + " " 286 + value + (token != null ? " " + token : "") 287 + (makeDefault ? " default" : "")); 288 289 } break; 290 291 case SETTING_TYPE_SECURE: { 292 executeShellCommand("settings put secure " + name + " " 293 + value + (token != null ? " " + token : "") 294 + (makeDefault ? " default" : "")); 295 } break; 296 297 case SETTING_TYPE_SYSTEM: { 298 executeShellCommand("settings put system " + name + " " 299 + value + (token != null ? " " + token : "") 300 + (makeDefault ? " default" : "")); 301 } break; 302 303 default: { 304 throw new IllegalArgumentException("Invalid type: " + type); 305 } 306 } 307 } 308 getContext()309 protected Context getContext() { 310 return InstrumentationRegistry.getContext(); 311 } 312 getSecondaryUserId()313 protected int getSecondaryUserId() { 314 if (mSecondaryUserId == Integer.MIN_VALUE) { 315 UserManager userManager = (UserManager) getContext() 316 .getSystemService(Context.USER_SERVICE); 317 List<UserInfo> users = userManager.getUsers(); 318 final int userCount = users.size(); 319 for (int i = 0; i < userCount; i++) { 320 UserInfo user = users.get(i); 321 if (!user.isPrimary() && !user.isManagedProfile()) { 322 mSecondaryUserId = user.id; 323 return mSecondaryUserId; 324 } 325 } 326 } 327 if (mSecondaryUserId == Integer.MIN_VALUE) { 328 mSecondaryUserId = UserHandle.USER_SYSTEM; 329 } 330 return mSecondaryUserId; 331 } 332 getBaseUriForType(int type)333 protected static Uri getBaseUriForType(int type) { 334 switch (type) { 335 case SETTING_TYPE_GLOBAL: { 336 return Settings.Global.CONTENT_URI; 337 } 338 339 case SETTING_TYPE_SECURE: { 340 return Settings.Secure.CONTENT_URI; 341 } 342 343 case SETTING_TYPE_SYSTEM: { 344 return Settings.System.CONTENT_URI; 345 } 346 347 default: { 348 throw new IllegalArgumentException("Invalid type: " + type); 349 } 350 } 351 } 352 executeShellCommand(String command)353 protected static void executeShellCommand(String command) throws IOException { 354 InputStream is = new FileInputStream(InstrumentationRegistry.getInstrumentation() 355 .getUiAutomation().executeShellCommand(command).getFileDescriptor()); 356 Streams.readFully(is); 357 } 358 } 359