1 /* 2 * Copyright (C) 2019 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.settings.validators; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.content.ComponentName; 22 import android.net.Uri; 23 import android.text.TextUtils; 24 25 import org.json.JSONException; 26 import org.json.JSONObject; 27 28 import java.util.Locale; 29 30 /** 31 * This class provides both interface for validation and common validators 32 * used to ensure Settings have meaningful values. 33 * 34 * @hide 35 */ 36 public class SettingsValidators { 37 38 public static final Validator BOOLEAN_VALIDATOR = 39 new DiscreteValueValidator(new String[] {"0", "1"}); 40 41 public static final Validator ANY_STRING_VALIDATOR = new Validator() { 42 @Override 43 public boolean validate(@Nullable String value) { 44 return true; 45 } 46 }; 47 48 public static final Validator NON_NEGATIVE_INTEGER_VALIDATOR = new Validator() { 49 @Override 50 public boolean validate(@Nullable String value) { 51 if (value == null) { 52 return true; 53 } 54 try { 55 return Integer.parseInt(value) >= 0; 56 } catch (NumberFormatException e) { 57 return false; 58 } 59 } 60 }; 61 62 public static final Validator ANY_INTEGER_VALIDATOR = new Validator() { 63 @Override 64 public boolean validate(@Nullable String value) { 65 if (value == null) { 66 return true; 67 } 68 try { 69 Integer.parseInt(value); 70 return true; 71 } catch (NumberFormatException e) { 72 return false; 73 } 74 } 75 }; 76 77 public static final Validator NON_NEGATIVE_FLOAT_VALIDATOR = new Validator() { 78 @Override 79 public boolean validate(@Nullable String value) { 80 if (value == null) { 81 return true; 82 } 83 try { 84 return Float.parseFloat(value) >= 0.0f; 85 } catch (NumberFormatException e) { 86 return false; 87 } 88 } 89 }; 90 91 public static final Validator URI_VALIDATOR = new Validator() { 92 @Override 93 public boolean validate(@Nullable String value) { 94 if (value == null) { 95 return true; 96 } 97 try { 98 Uri.decode(value); 99 return true; 100 } catch (IllegalArgumentException e) { 101 return false; 102 } 103 } 104 }; 105 106 /** 107 * Does not allow a setting to have a null {@link ComponentName}. Use {@link 108 * SettingsValidators#NULLABLE_COMPONENT_NAME_VALIDATOR} instead if a setting can have a 109 * nullable {@link ComponentName}. 110 */ 111 public static final Validator COMPONENT_NAME_VALIDATOR = new Validator() { 112 @Override 113 public boolean validate(@NonNull String value) { 114 return value != null && ComponentName.unflattenFromString(value) != null; 115 } 116 }; 117 118 /** 119 * Allows a setting to have a null {@link ComponentName}. 120 */ 121 public static final Validator NULLABLE_COMPONENT_NAME_VALIDATOR = new Validator() { 122 @Override 123 public boolean validate(@Nullable String value) { 124 return value == null || COMPONENT_NAME_VALIDATOR.validate(value); 125 } 126 }; 127 128 public static final Validator PACKAGE_NAME_VALIDATOR = new Validator() { 129 @Override 130 public boolean validate(@NonNull String value) { 131 return value != null && isStringPackageName(value); 132 } 133 134 private boolean isStringPackageName(@NonNull String value) { 135 // The name may contain uppercase or lowercase letters ('A' through 'Z'), numbers, 136 // and underscores ('_'). However, individual package name parts may only 137 // start with letters. 138 // (https://developer.android.com/guide/topics/manifest/manifest-element.html#package) 139 String[] subparts = value.split("\\."); 140 boolean isValidPackageName = true; 141 for (String subpart : subparts) { 142 isValidPackageName &= isSubpartValidForPackageName(subpart); 143 if (!isValidPackageName) break; 144 } 145 return isValidPackageName; 146 } 147 148 private boolean isSubpartValidForPackageName(String subpart) { 149 if (subpart.length() == 0) return false; 150 boolean isValidSubpart = Character.isLetter(subpart.charAt(0)); 151 for (int i = 1; i < subpart.length(); i++) { 152 isValidSubpart &= (Character.isLetterOrDigit(subpart.charAt(i)) 153 || (subpart.charAt(i) == '_')); 154 if (!isValidSubpart) break; 155 } 156 return isValidSubpart; 157 } 158 }; 159 160 public static final Validator LENIENT_IP_ADDRESS_VALIDATOR = new Validator() { 161 private static final int MAX_IPV6_LENGTH = 45; 162 163 @Override 164 public boolean validate(@Nullable String value) { 165 if (value == null) { 166 return true; 167 } 168 return value.length() <= MAX_IPV6_LENGTH; 169 } 170 }; 171 172 public static final Validator LOCALE_VALIDATOR = new Validator() { 173 @Override 174 public boolean validate(@Nullable String value) { 175 if (value == null) { 176 return true; 177 } 178 Locale[] validLocales = Locale.getAvailableLocales(); 179 for (Locale locale : validLocales) { 180 if (value.equals(locale.toString())) { 181 return true; 182 } 183 } 184 return false; 185 } 186 }; 187 188 /** {@link Validator} that checks whether a value is a valid {@link JSONObject}. */ 189 public static final Validator JSON_OBJECT_VALIDATOR = (value) -> { 190 if (value == null) { 191 return true; 192 } 193 if (TextUtils.isEmpty(value)) { 194 return false; 195 } 196 try { 197 new JSONObject(value); 198 return true; 199 } catch (JSONException e) { 200 return false; 201 } 202 }; 203 204 public static final Validator TTS_LIST_VALIDATOR = new TTSListValidator(); 205 206 public static final Validator TILE_LIST_VALIDATOR = new TileListValidator(); 207 208 static final Validator COLON_SEPARATED_COMPONENT_LIST_VALIDATOR = 209 new ComponentNameListValidator(":"); 210 211 static final Validator COLON_SEPARATED_PACKAGE_LIST_VALIDATOR = 212 new PackageNameListValidator(":"); 213 214 static final Validator COMMA_SEPARATED_COMPONENT_LIST_VALIDATOR = 215 new ComponentNameListValidator(","); 216 217 static final Validator PERCENTAGE_INTEGER_VALIDATOR = 218 new InclusiveIntegerRangeValidator(0, 100); 219 220 static final Validator VIBRATION_INTENSITY_VALIDATOR = new InclusiveIntegerRangeValidator(0, 3); 221 222 static final Validator ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR = 223 new AccessibilityShortcutTargetListValidator(); 224 225 static final Validator NONE_NEGATIVE_LONG_VALIDATOR = new Validator() { 226 @Override 227 public boolean validate(String value) { 228 if (value == null) { 229 return true; 230 } 231 try { 232 return Long.parseLong(value) >= 0; 233 } catch (NumberFormatException e) { 234 return false; 235 } 236 } 237 }; 238 } 239