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