12c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski/*
22c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski * Copyright (C) 2018 The Android Open Source Project
32c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski *
42c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski * Licensed under the Apache License, Version 2.0 (the "License");
52c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski * you may not use this file except in compliance with the License.
62c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski * You may obtain a copy of the License at
72c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski *
82c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski *      http://www.apache.org/licenses/LICENSE-2.0
92c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski *
102c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski * Unless required by applicable law or agreed to in writing, software
112c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski * distributed under the License is distributed on an "AS IS" BASIS,
122c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski * See the License for the specific language governing permissions and
142c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski * limitations under the License.
152c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski */
162c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
172c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinskipackage android.provider;
182c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
19eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Mengimport android.annotation.Nullable;
202c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinskiimport android.content.ComponentName;
212c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinskiimport android.net.Uri;
222c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
232c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinskiimport com.android.internal.util.ArrayUtils;
242c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
25964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinskiimport java.util.Locale;
26964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski
272c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski/**
282c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski * This class provides both interface for validation and common validators
292c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski * used to ensure Settings have meaningful values.
302c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski *
312c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski * @hide
322c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski */
332c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinskipublic class SettingsValidators {
342c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
352c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski    public static final Validator BOOLEAN_VALIDATOR =
362c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski            new DiscreteValueValidator(new String[] {"0", "1"});
372c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
385db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski    public static final Validator ANY_STRING_VALIDATOR = new Validator() {
395db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski        @Override
40eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Meng        public boolean validate(@Nullable String value) {
415db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski            return true;
425db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski        }
435db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski    };
445db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski
452c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski    public static final Validator NON_NEGATIVE_INTEGER_VALIDATOR = new Validator() {
462c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        @Override
47eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Meng        public boolean validate(@Nullable String value) {
482c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski            try {
492c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski                return Integer.parseInt(value) >= 0;
502c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski            } catch (NumberFormatException e) {
512c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski                return false;
522c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski            }
532c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        }
542c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski    };
552c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
56964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski    public static final Validator ANY_INTEGER_VALIDATOR = new Validator() {
57964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski        @Override
58eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Meng        public boolean validate(@Nullable String value) {
59964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            try {
60964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski                Integer.parseInt(value);
61964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski                return true;
62964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            } catch (NumberFormatException e) {
63964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski                return false;
64964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            }
65964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski        }
66964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski    };
67964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski
682c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski    public static final Validator URI_VALIDATOR = new Validator() {
692c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        @Override
70eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Meng        public boolean validate(@Nullable String value) {
712c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski            try {
722c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski                Uri.decode(value);
732c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski                return true;
742c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski            } catch (IllegalArgumentException e) {
752c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski                return false;
762c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski            }
772c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        }
782c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski    };
792c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
804451179411f4a84d2b64c5306371b186e510ad3cAnnie Meng    /**
814451179411f4a84d2b64c5306371b186e510ad3cAnnie Meng     * Does not allow a setting to have a null {@link ComponentName}. Use {@link
824451179411f4a84d2b64c5306371b186e510ad3cAnnie Meng     * SettingsValidators#NULLABLE_COMPONENT_NAME_VALIDATOR} instead if a setting can have a
834451179411f4a84d2b64c5306371b186e510ad3cAnnie Meng     * nullable {@link ComponentName}.
844451179411f4a84d2b64c5306371b186e510ad3cAnnie Meng     */
852c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski    public static final Validator COMPONENT_NAME_VALIDATOR = new Validator() {
862c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        @Override
87eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Meng        public boolean validate(@Nullable String value) {
885d26b8c03a1e11076e41699fd54259ef5ff4a1e0Annie Meng            return value != null && ComponentName.unflattenFromString(value) != null;
892c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        }
902c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski    };
912c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
924451179411f4a84d2b64c5306371b186e510ad3cAnnie Meng    /**
934451179411f4a84d2b64c5306371b186e510ad3cAnnie Meng     * Allows a setting to have a null {@link ComponentName}.
944451179411f4a84d2b64c5306371b186e510ad3cAnnie Meng     */
954451179411f4a84d2b64c5306371b186e510ad3cAnnie Meng    public static final Validator NULLABLE_COMPONENT_NAME_VALIDATOR = new Validator() {
964451179411f4a84d2b64c5306371b186e510ad3cAnnie Meng        @Override
974451179411f4a84d2b64c5306371b186e510ad3cAnnie Meng        public boolean validate(@Nullable String value) {
984451179411f4a84d2b64c5306371b186e510ad3cAnnie Meng            return value == null || COMPONENT_NAME_VALIDATOR.validate(value);
994451179411f4a84d2b64c5306371b186e510ad3cAnnie Meng        }
1004451179411f4a84d2b64c5306371b186e510ad3cAnnie Meng    };
1014451179411f4a84d2b64c5306371b186e510ad3cAnnie Meng
1025db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski    public static final Validator PACKAGE_NAME_VALIDATOR = new Validator() {
1035db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski        @Override
104eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Meng        public boolean validate(@Nullable String value) {
1055db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski            return value != null && isStringPackageName(value);
1065db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski        }
1075db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski
1085db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski        private boolean isStringPackageName(String value) {
1095db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski            // The name may contain uppercase or lowercase letters ('A' through 'Z'), numbers,
1105db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski            // and underscores ('_'). However, individual package name parts may only
1115db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski            // start with letters.
1125db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski            // (https://developer.android.com/guide/topics/manifest/manifest-element.html#package)
113964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            if (value == null) {
114964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski                return false;
115964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            }
11629a7472974d4c90c1668eb24db83f27ca17012cdMichal Karpinski            String[] subparts = value.split("\\.");
1175db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski            boolean isValidPackageName = true;
1185db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski            for (String subpart : subparts) {
1196fe6c8ef02df1c394cab1316248e1ffb88c598a1Michal Karpinski                isValidPackageName &= isSubpartValidForPackageName(subpart);
1205db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski                if (!isValidPackageName) break;
1215db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski            }
1225db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski            return isValidPackageName;
1235db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski        }
1245db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski
1255db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski        private boolean isSubpartValidForPackageName(String subpart) {
1265db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski            if (subpart.length() == 0) return false;
1275db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski            boolean isValidSubpart = Character.isLetter(subpart.charAt(0));
1285db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski            for (int i = 1; i < subpart.length(); i++) {
1296fe6c8ef02df1c394cab1316248e1ffb88c598a1Michal Karpinski                isValidSubpart &= (Character.isLetterOrDigit(subpart.charAt(i))
1305db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski                                || (subpart.charAt(i) == '_'));
1315db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski                if (!isValidSubpart) break;
1325db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski            }
1335db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski            return isValidSubpart;
1345db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski        }
1355db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski    };
1365db1e430f9d774a5b203eda5ec53f065bb1ec5b3Michal Karpinski
1372c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski    public static final Validator LENIENT_IP_ADDRESS_VALIDATOR = new Validator() {
1382c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        private static final int MAX_IPV6_LENGTH = 45;
1392c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
1402c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        @Override
141eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Meng        public boolean validate(@Nullable String value) {
142964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            if (value == null) {
143964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski                return false;
144964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            }
1452c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski            return value.length() <= MAX_IPV6_LENGTH;
1462c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        }
1472c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski    };
1482c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
149964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski    public static final Validator LOCALE_VALIDATOR = new Validator() {
150964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski        @Override
151eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Meng        public boolean validate(@Nullable String value) {
152964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            if (value == null) {
153964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski                return false;
154964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            }
155964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            Locale[] validLocales = Locale.getAvailableLocales();
156964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            for (Locale locale : validLocales) {
157964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski                if (value.equals(locale.toString())) {
158964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski                    return true;
159964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski                }
160964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            }
161964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            return false;
162964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski        }
163964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski    };
164964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski
1652c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski    public interface Validator {
166eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Meng        /**
167eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Meng         * Returns whether the input value is valid. Subclasses should handle the case where the
168eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Meng         * input value is {@code null}.
169eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Meng         */
170eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Meng        boolean validate(@Nullable String value);
1712c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski    }
1722c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
1732c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski    public static final class DiscreteValueValidator implements Validator {
1742c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        private final String[] mValues;
1752c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
1762c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        public DiscreteValueValidator(String[] values) {
1772c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski            mValues = values;
1782c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        }
1792c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
1802c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        @Override
181eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Meng        public boolean validate(@Nullable String value) {
1822c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski            return ArrayUtils.contains(mValues, value);
1832c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        }
1842c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski    }
1852c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
1862c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski    public static final class InclusiveIntegerRangeValidator implements Validator {
1872c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        private final int mMin;
1882c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        private final int mMax;
1892c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
1902c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        public InclusiveIntegerRangeValidator(int min, int max) {
1912c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski            mMin = min;
1922c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski            mMax = max;
1932c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        }
1942c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
1952c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        @Override
196eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Meng        public boolean validate(@Nullable String value) {
1972c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski            try {
1982c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski                final int intValue = Integer.parseInt(value);
1992c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski                return intValue >= mMin && intValue <= mMax;
2002c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski            } catch (NumberFormatException e) {
2012c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski                return false;
2022c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski            }
2032c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        }
2042c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski    }
2052c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
2062c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski    public static final class InclusiveFloatRangeValidator implements Validator {
2072c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        private final float mMin;
2082c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        private final float mMax;
2092c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
2102c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        public InclusiveFloatRangeValidator(float min, float max) {
2112c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski            mMin = min;
2122c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski            mMax = max;
2132c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        }
2142c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski
2152c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        @Override
216eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Meng        public boolean validate(@Nullable String value) {
2172c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski            try {
2182c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski                final float floatValue = Float.parseFloat(value);
2192c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski                return floatValue >= mMin && floatValue <= mMax;
220eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Meng            } catch (NumberFormatException | NullPointerException e) {
2212c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski                return false;
2222c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski            }
2232c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski        }
2242c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski    }
225964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski
226964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski    public static final class ComponentNameListValidator implements Validator {
227964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski        private final String mSeparator;
228964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski
229964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski        public ComponentNameListValidator(String separator) {
230964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            mSeparator = separator;
231964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski        }
232964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski
233964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski        @Override
234eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Meng        public boolean validate(@Nullable String value) {
235964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            if (value == null) {
236964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski                return false;
237964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            }
238964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            String[] elements = value.split(mSeparator);
239964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            for (String element : elements) {
240964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski                if (!COMPONENT_NAME_VALIDATOR.validate(element)) {
241964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski                    return false;
242964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski                }
243964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            }
244964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            return true;
245964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski        }
246964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski    }
247964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski
248964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski    public static final class PackageNameListValidator implements Validator {
249964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski        private final String mSeparator;
250964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski
251964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski        public PackageNameListValidator(String separator) {
252964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            mSeparator = separator;
253964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski        }
254964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski
255964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski        @Override
256eed1b812a4ad38c6815f3066e41a95d7f5358838Annie Meng        public boolean validate(@Nullable String value) {
257964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            if (value == null) {
258964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski                return false;
259964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            }
260964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            String[] elements = value.split(mSeparator);
261964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            for (String element : elements) {
262964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski                if (!PACKAGE_NAME_VALIDATOR.validate(element)) {
263964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski                    return false;
264964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski                }
265964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            }
266964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski            return true;
267964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski        }
268964943ab98874a91be04f9ea2137861c93f6ffd3Michal Karpinski    }
2692c37b08510877af06542ad21eb5b63c8f9824584Michal Karpinski}
270