• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.safetycenter.config;
18 
19 import static android.os.Build.VERSION_CODES.TIRAMISU;
20 
21 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
22 import static org.xmlpull.v1.XmlPullParser.END_TAG;
23 import static org.xmlpull.v1.XmlPullParser.FEATURE_PROCESS_NAMESPACES;
24 import static org.xmlpull.v1.XmlPullParser.START_DOCUMENT;
25 import static org.xmlpull.v1.XmlPullParser.START_TAG;
26 import static org.xmlpull.v1.XmlPullParser.TEXT;
27 
28 import static java.util.Locale.ROOT;
29 import static java.util.Objects.requireNonNull;
30 
31 import android.annotation.StringRes;
32 import android.content.res.Resources;
33 import android.safetycenter.config.SafetyCenterConfig;
34 import android.safetycenter.config.SafetySource;
35 import android.safetycenter.config.SafetySourcesGroup;
36 
37 import androidx.annotation.RequiresApi;
38 
39 import com.android.modules.utils.build.SdkLevel;
40 
41 import org.xmlpull.v1.XmlPullParser;
42 import org.xmlpull.v1.XmlPullParserException;
43 import org.xmlpull.v1.XmlPullParserFactory;
44 
45 import java.io.IOException;
46 import java.io.InputStream;
47 
48 /** Parser and validator for {@link SafetyCenterConfig} objects. */
49 @RequiresApi(TIRAMISU)
50 public final class SafetyCenterConfigParser {
51 
52     private static final String TAG_SAFETY_CENTER_CONFIG = "safety-center-config";
53     private static final String TAG_SAFETY_SOURCES_CONFIG = "safety-sources-config";
54     private static final String TAG_SAFETY_SOURCES_GROUP = "safety-sources-group";
55     private static final String TAG_STATIC_SAFETY_SOURCE = "static-safety-source";
56     private static final String TAG_DYNAMIC_SAFETY_SOURCE = "dynamic-safety-source";
57     private static final String TAG_ISSUE_ONLY_SAFETY_SOURCE = "issue-only-safety-source";
58     private static final String ATTR_SAFETY_SOURCES_GROUP_ID = "id";
59     private static final String ATTR_SAFETY_SOURCES_GROUP_TITLE = "title";
60     private static final String ATTR_SAFETY_SOURCES_GROUP_SUMMARY = "summary";
61     private static final String ATTR_SAFETY_SOURCES_GROUP_STATELESS_ICON_TYPE = "statelessIconType";
62     private static final String ATTR_SAFETY_SOURCES_GROUP_TYPE = "type";
63     private static final String ATTR_SAFETY_SOURCE_ID = "id";
64     private static final String ATTR_SAFETY_SOURCE_PACKAGE_NAME = "packageName";
65     private static final String ATTR_SAFETY_SOURCE_TITLE = "title";
66     private static final String ATTR_SAFETY_SOURCE_TITLE_FOR_WORK = "titleForWork";
67     private static final String ATTR_SAFETY_SOURCE_SUMMARY = "summary";
68     private static final String ATTR_SAFETY_SOURCE_INTENT_ACTION = "intentAction";
69     private static final String ATTR_SAFETY_SOURCE_PROFILE = "profile";
70     private static final String ATTR_SAFETY_SOURCE_INITIAL_DISPLAY_STATE = "initialDisplayState";
71     private static final String ATTR_SAFETY_SOURCE_MAX_SEVERITY_LEVEL = "maxSeverityLevel";
72     private static final String ATTR_SAFETY_SOURCE_SEARCH_TERMS = "searchTerms";
73     private static final String ATTR_SAFETY_SOURCE_LOGGING_ALLOWED = "loggingAllowed";
74     private static final String ATTR_SAFETY_SOURCE_REFRESH_ON_PAGE_OPEN_ALLOWED =
75             "refreshOnPageOpenAllowed";
76     private static final String ATTR_SAFETY_SOURCE_NOTIFICATIONS_ALLOWED = "notificationsAllowed";
77     private static final String ATTR_SAFETY_SOURCE_DEDUPLICATION_GROUP = "deduplicationGroup";
78     private static final String ATTR_SAFETY_SOURCE_PACKAGE_CERT_HASHES = "packageCertificateHashes";
79     private static final String ENUM_STATELESS_ICON_TYPE_NONE = "none";
80     private static final String ENUM_STATELESS_ICON_TYPE_PRIVACY = "privacy";
81     private static final String ENUM_GROUP_TYPE_STATEFUL = "stateful";
82     private static final String ENUM_GROUP_TYPE_STATELESS = "stateless";
83     private static final String ENUM_GROUP_TYPE_HIDDEN = "hidden";
84     private static final String ENUM_PROFILE_PRIMARY = "primary_profile_only";
85     private static final String ENUM_PROFILE_ALL = "all_profiles";
86     private static final String ENUM_INITIAL_DISPLAY_STATE_ENABLED = "enabled";
87     private static final String ENUM_INITIAL_DISPLAY_STATE_DISABLED = "disabled";
88     private static final String ENUM_INITIAL_DISPLAY_STATE_HIDDEN = "hidden";
89 
SafetyCenterConfigParser()90     private SafetyCenterConfigParser() {}
91 
92     /**
93      * Parses and validates the given XML resource into a {@link SafetyCenterConfig} object.
94      *
95      * <p>It throws a {@link ParseException} if the given XML resource does not comply with the
96      * safety_center_config.xsd schema.
97      *
98      * @param in the raw XML resource representing the Safety Center configuration
99      * @param resources the {@link Resources} retrieved from the package that contains the Safety
100      *     Center configuration
101      */
parseXmlResource(InputStream in, Resources resources)102     public static SafetyCenterConfig parseXmlResource(InputStream in, Resources resources)
103             throws ParseException {
104         requireNonNull(in);
105         requireNonNull(resources);
106         try {
107             XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
108             parser.setFeature(FEATURE_PROCESS_NAMESPACES, true);
109             parser.setInput(in, null);
110             if (parser.getEventType() != START_DOCUMENT) {
111                 throw new ParseException("Unexpected parser state");
112             }
113             parser.nextTag();
114             validateElementStart(parser, TAG_SAFETY_CENTER_CONFIG);
115             SafetyCenterConfig safetyCenterConfig = parseSafetyCenterConfig(parser, resources);
116             if (parser.getEventType() == TEXT && parser.isWhitespace()) {
117                 parser.next();
118             }
119             if (parser.getEventType() != END_DOCUMENT) {
120                 throw new ParseException("Unexpected extra root element");
121             }
122             return safetyCenterConfig;
123         } catch (XmlPullParserException | IOException e) {
124             throw new ParseException("Exception while parsing the XML resource", e);
125         }
126     }
127 
parseSafetyCenterConfig( XmlPullParser parser, Resources resources)128     private static SafetyCenterConfig parseSafetyCenterConfig(
129             XmlPullParser parser, Resources resources)
130             throws XmlPullParserException, IOException, ParseException {
131         validateElementHasNoAttribute(parser, TAG_SAFETY_CENTER_CONFIG);
132         parser.nextTag();
133         validateElementStart(parser, TAG_SAFETY_SOURCES_CONFIG);
134         validateElementHasNoAttribute(parser, TAG_SAFETY_SOURCES_CONFIG);
135         SafetyCenterConfig.Builder builder = new SafetyCenterConfig.Builder();
136         parser.nextTag();
137         while (parser.getEventType() == START_TAG
138                 && parser.getName().equals(TAG_SAFETY_SOURCES_GROUP)) {
139             builder.addSafetySourcesGroup(parseSafetySourcesGroup(parser, resources));
140         }
141         validateElementEnd(parser, TAG_SAFETY_SOURCES_CONFIG);
142         parser.nextTag();
143         validateElementEnd(parser, TAG_SAFETY_CENTER_CONFIG);
144         parser.next();
145         try {
146             return builder.build();
147         } catch (IllegalStateException e) {
148             throw elementInvalid(TAG_SAFETY_SOURCES_CONFIG, e);
149         }
150     }
151 
parseSafetySourcesGroup( XmlPullParser parser, Resources resources)152     private static SafetySourcesGroup parseSafetySourcesGroup(
153             XmlPullParser parser, Resources resources)
154             throws XmlPullParserException, IOException, ParseException {
155         String name = TAG_SAFETY_SOURCES_GROUP;
156         SafetySourcesGroup.Builder builder = new SafetySourcesGroup.Builder();
157         for (int i = 0; i < parser.getAttributeCount(); i++) {
158             switch (parser.getAttributeName(i)) {
159                 case ATTR_SAFETY_SOURCES_GROUP_ID:
160                     builder.setId(
161                             parseStringResourceValue(
162                                     parser.getAttributeValue(i),
163                                     name,
164                                     parser.getAttributeName(i),
165                                     resources));
166                     break;
167                 case ATTR_SAFETY_SOURCES_GROUP_TITLE:
168                     builder.setTitleResId(
169                             parseStringResourceName(
170                                     parser.getAttributeValue(i),
171                                     name,
172                                     parser.getAttributeName(i),
173                                     resources));
174                     break;
175                 case ATTR_SAFETY_SOURCES_GROUP_SUMMARY:
176                     builder.setSummaryResId(
177                             parseStringResourceName(
178                                     parser.getAttributeValue(i),
179                                     name,
180                                     parser.getAttributeName(i),
181                                     resources));
182                     break;
183                 case ATTR_SAFETY_SOURCES_GROUP_STATELESS_ICON_TYPE:
184                     builder.setStatelessIconType(
185                             parseStatelessIconType(
186                                     parser.getAttributeValue(i),
187                                     name,
188                                     parser.getAttributeName(i),
189                                     resources));
190                     break;
191                 case ATTR_SAFETY_SOURCES_GROUP_TYPE:
192                     if (SdkLevel.isAtLeastU()) {
193                         builder.setType(
194                                 parseGroupType(
195                                         parser.getAttributeValue(i),
196                                         name,
197                                         parser.getAttributeName(i),
198                                         resources));
199                     } else {
200                         throw attributeUnexpected(name, parser.getAttributeName(i));
201                     }
202                     break;
203                 default:
204                     throw attributeUnexpected(name, parser.getAttributeName(i));
205             }
206         }
207         parser.nextTag();
208         loop:
209         while (parser.getEventType() == START_TAG) {
210             int type;
211             switch (parser.getName()) {
212                 case TAG_STATIC_SAFETY_SOURCE:
213                     type = SafetySource.SAFETY_SOURCE_TYPE_STATIC;
214                     break;
215                 case TAG_DYNAMIC_SAFETY_SOURCE:
216                     type = SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC;
217                     break;
218                 case TAG_ISSUE_ONLY_SAFETY_SOURCE:
219                     type = SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY;
220                     break;
221                 default:
222                     break loop;
223             }
224             builder.addSafetySource(parseSafetySource(parser, resources, type, parser.getName()));
225         }
226         validateElementEnd(parser, name);
227         parser.nextTag();
228         try {
229             return builder.build();
230         } catch (IllegalStateException e) {
231             throw elementInvalid(name, e);
232         }
233     }
234 
parseSafetySource( XmlPullParser parser, Resources resources, int safetySourceType, String name)235     private static SafetySource parseSafetySource(
236             XmlPullParser parser, Resources resources, int safetySourceType, String name)
237             throws XmlPullParserException, IOException, ParseException {
238         SafetySource.Builder builder = new SafetySource.Builder(safetySourceType);
239         for (int i = 0; i < parser.getAttributeCount(); i++) {
240             switch (parser.getAttributeName(i)) {
241                 case ATTR_SAFETY_SOURCE_ID:
242                     builder.setId(
243                             parseStringResourceValue(
244                                     parser.getAttributeValue(i),
245                                     name,
246                                     parser.getAttributeName(i),
247                                     resources));
248                     break;
249                 case ATTR_SAFETY_SOURCE_PACKAGE_NAME:
250                     builder.setPackageName(
251                             parseStringResourceValue(
252                                     parser.getAttributeValue(i),
253                                     name,
254                                     parser.getAttributeName(i),
255                                     resources));
256                     break;
257                 case ATTR_SAFETY_SOURCE_TITLE:
258                     builder.setTitleResId(
259                             parseStringResourceName(
260                                     parser.getAttributeValue(i),
261                                     name,
262                                     parser.getAttributeName(i),
263                                     resources));
264                     break;
265                 case ATTR_SAFETY_SOURCE_TITLE_FOR_WORK:
266                     builder.setTitleForWorkResId(
267                             parseStringResourceName(
268                                     parser.getAttributeValue(i),
269                                     name,
270                                     parser.getAttributeName(i),
271                                     resources));
272                     break;
273                 case ATTR_SAFETY_SOURCE_SUMMARY:
274                     builder.setSummaryResId(
275                             parseStringResourceName(
276                                     parser.getAttributeValue(i),
277                                     name,
278                                     parser.getAttributeName(i),
279                                     resources));
280                     break;
281                 case ATTR_SAFETY_SOURCE_INTENT_ACTION:
282                     builder.setIntentAction(
283                             parseStringResourceValue(
284                                     parser.getAttributeValue(i),
285                                     name,
286                                     parser.getAttributeName(i),
287                                     resources));
288                     break;
289                 case ATTR_SAFETY_SOURCE_PROFILE:
290                     builder.setProfile(
291                             parseProfile(
292                                     parser.getAttributeValue(i),
293                                     name,
294                                     parser.getAttributeName(i),
295                                     resources));
296                     break;
297                 case ATTR_SAFETY_SOURCE_INITIAL_DISPLAY_STATE:
298                     builder.setInitialDisplayState(
299                             parseInitialDisplayState(
300                                     parser.getAttributeValue(i),
301                                     name,
302                                     parser.getAttributeName(i),
303                                     resources));
304                     break;
305                 case ATTR_SAFETY_SOURCE_MAX_SEVERITY_LEVEL:
306                     builder.setMaxSeverityLevel(
307                             parseInteger(
308                                     parser.getAttributeValue(i),
309                                     name,
310                                     parser.getAttributeName(i),
311                                     resources));
312                     break;
313                 case ATTR_SAFETY_SOURCE_SEARCH_TERMS:
314                     builder.setSearchTermsResId(
315                             parseStringResourceName(
316                                     parser.getAttributeValue(i),
317                                     name,
318                                     parser.getAttributeName(i),
319                                     resources));
320                     break;
321                 case ATTR_SAFETY_SOURCE_LOGGING_ALLOWED:
322                     builder.setLoggingAllowed(
323                             parseBoolean(
324                                     parser.getAttributeValue(i),
325                                     name,
326                                     parser.getAttributeName(i),
327                                     resources));
328                     break;
329                 case ATTR_SAFETY_SOURCE_REFRESH_ON_PAGE_OPEN_ALLOWED:
330                     builder.setRefreshOnPageOpenAllowed(
331                             parseBoolean(
332                                     parser.getAttributeValue(i),
333                                     name,
334                                     parser.getAttributeName(i),
335                                     resources));
336                     break;
337                 case ATTR_SAFETY_SOURCE_NOTIFICATIONS_ALLOWED:
338                     if (SdkLevel.isAtLeastU()) {
339                         builder.setNotificationsAllowed(
340                                 parseBoolean(
341                                         parser.getAttributeValue(i),
342                                         name,
343                                         parser.getAttributeName(i),
344                                         resources));
345                     } else {
346                         throw attributeUnexpected(name, parser.getAttributeName(i));
347                     }
348                     break;
349                 case ATTR_SAFETY_SOURCE_DEDUPLICATION_GROUP:
350                     if (SdkLevel.isAtLeastU()) {
351                         builder.setDeduplicationGroup(
352                                 parseStringResourceValue(
353                                         parser.getAttributeValue(i),
354                                         name,
355                                         parser.getAttributeName(i),
356                                         resources));
357                     } else {
358                         throw attributeUnexpected(name, parser.getAttributeName(i));
359                     }
360                     break;
361                 case ATTR_SAFETY_SOURCE_PACKAGE_CERT_HASHES:
362                     if (SdkLevel.isAtLeastU()) {
363                         String commaSeparatedHashes =
364                                 parseStringResourceValue(
365                                         parser.getAttributeValue(i),
366                                         name,
367                                         parser.getAttributeName(i),
368                                         resources);
369                         String[] splits = commaSeparatedHashes.split(",");
370                         for (int j = 0; j < splits.length; j++) {
371                             builder.addPackageCertificateHash(splits[j]);
372                         }
373                     } else {
374                         throw attributeUnexpected(name, parser.getAttributeName(i));
375                     }
376                     break;
377                 default:
378                     throw attributeUnexpected(name, parser.getAttributeName(i));
379             }
380         }
381         parser.nextTag();
382         validateElementEnd(parser, name);
383         parser.nextTag();
384         try {
385             return builder.build();
386         } catch (IllegalStateException e) {
387             throw elementInvalid(name, e);
388         }
389     }
390 
validateElementStart(XmlPullParser parser, String name)391     private static void validateElementStart(XmlPullParser parser, String name)
392             throws XmlPullParserException, ParseException {
393         if (parser.getEventType() != START_TAG || !parser.getName().equals(name)) {
394             throw elementMissing(name);
395         }
396     }
397 
validateElementEnd(XmlPullParser parser, String name)398     private static void validateElementEnd(XmlPullParser parser, String name)
399             throws XmlPullParserException, ParseException {
400         if (parser.getEventType() != END_TAG || !parser.getName().equals(name)) {
401             throw elementNotClosed(name);
402         }
403     }
404 
validateElementHasNoAttribute(XmlPullParser parser, String name)405     private static void validateElementHasNoAttribute(XmlPullParser parser, String name)
406             throws ParseException {
407         if (parser.getAttributeCount() != 0) {
408             throw elementInvalid(name);
409         }
410     }
411 
elementMissing(String name)412     private static ParseException elementMissing(String name) {
413         return new ParseException(String.format("Element %s missing", name));
414     }
415 
elementNotClosed(String name)416     private static ParseException elementNotClosed(String name) {
417         return new ParseException(String.format("Element %s not closed", name));
418     }
419 
elementInvalid(String name)420     private static ParseException elementInvalid(String name) {
421         return new ParseException(String.format("Element %s invalid", name));
422     }
423 
elementInvalid(String name, Throwable e)424     private static ParseException elementInvalid(String name, Throwable e) {
425         return new ParseException(String.format("Element %s invalid", name), e);
426     }
427 
attributeUnexpected(String parent, String name)428     private static ParseException attributeUnexpected(String parent, String name) {
429         return new ParseException(String.format("Unexpected attribute %s.%s", parent, name));
430     }
431 
attributeInvalidString(String valueString, String parent, String name)432     private static String attributeInvalidString(String valueString, String parent, String name) {
433         return String.format("Attribute value \"%s\" in %s.%s invalid", valueString, parent, name);
434     }
435 
attributeInvalid(String valueString, String parent, String name)436     private static ParseException attributeInvalid(String valueString, String parent, String name) {
437         return new ParseException(attributeInvalidString(valueString, parent, name));
438     }
439 
attributeInvalid( String valueString, String parent, String name, Throwable ex)440     private static ParseException attributeInvalid(
441             String valueString, String parent, String name, Throwable ex) {
442         return new ParseException(attributeInvalidString(valueString, parent, name), ex);
443     }
444 
parseInteger( String valueString, String parent, String name, Resources resources)445     private static int parseInteger(
446             String valueString, String parent, String name, Resources resources)
447             throws ParseException {
448         String valueToParse = getValueToParse(valueString, parent, name, resources);
449         try {
450             return Integer.parseInt(valueToParse);
451         } catch (NumberFormatException e) {
452             throw attributeInvalid(valueToParse, parent, name, e);
453         }
454     }
455 
parseBoolean( String valueString, String parent, String name, Resources resources)456     private static boolean parseBoolean(
457             String valueString, String parent, String name, Resources resources)
458             throws ParseException {
459         String valueToParse =
460                 getValueToParse(valueString, parent, name, resources).toLowerCase(ROOT);
461         if (valueToParse.equals("true")) {
462             return true;
463         } else if (!valueToParse.equals("false")) {
464             throw attributeInvalid(valueToParse, parent, name);
465         }
466         return false;
467     }
468 
469     @StringRes
parseStringResourceName( String valueString, String parent, String name, Resources resources)470     private static int parseStringResourceName(
471             String valueString, String parent, String name, Resources resources)
472             throws ParseException {
473         if (valueString.isEmpty()) {
474             throw new ParseException(
475                     String.format("Resource name in %s.%s cannot be empty", parent, name));
476         }
477         if (valueString.charAt(0) != '@') {
478             throw new ParseException(
479                     String.format(
480                             "Resource name \"%s\" in %s.%s does not start with @",
481                             valueString, parent, name));
482         }
483         String[] colonSplit = valueString.substring(1).split(":", 2);
484         if (colonSplit.length != 2 || colonSplit[0].isEmpty()) {
485             throw new ParseException(
486                     String.format(
487                             "Resource name \"%s\" in %s.%s does not specify a package",
488                             valueString, parent, name));
489         }
490         String packageName = colonSplit[0];
491         String[] slashSplit = colonSplit[1].split("/", 2);
492         if (slashSplit.length != 2 || slashSplit[0].isEmpty()) {
493             throw new ParseException(
494                     String.format(
495                             "Resource name \"%s\" in %s.%s does not specify a type",
496                             valueString, parent, name));
497         }
498         String type = slashSplit[0];
499         if (!type.equals("string")) {
500             throw new ParseException(
501                     String.format(
502                             "Resource name \"%s\" in %s.%s is not a string",
503                             valueString, parent, name));
504         }
505         String entry = slashSplit[1];
506         int id = resources.getIdentifier(entry, type, packageName);
507         if (id == Resources.ID_NULL) {
508             throw new ParseException(
509                     String.format(
510                             "Resource name \"%s\" in %s.%s missing or invalid",
511                             valueString, parent, name));
512         }
513         return id;
514     }
515 
parseStringResourceValue( String valueString, String parent, String name, Resources resources)516     private static String parseStringResourceValue(
517             String valueString, String parent, String name, Resources resources) {
518         return getValueToParse(valueString, parent, name, resources);
519     }
520 
parseStatelessIconType( String valueString, String parent, String name, Resources resources)521     private static int parseStatelessIconType(
522             String valueString, String parent, String name, Resources resources)
523             throws ParseException {
524         String valueToParse = getValueToParse(valueString, parent, name, resources);
525         switch (valueToParse) {
526             case ENUM_STATELESS_ICON_TYPE_NONE:
527                 return SafetySourcesGroup.STATELESS_ICON_TYPE_NONE;
528             case ENUM_STATELESS_ICON_TYPE_PRIVACY:
529                 return SafetySourcesGroup.STATELESS_ICON_TYPE_PRIVACY;
530             default:
531                 throw attributeInvalid(valueToParse, parent, name);
532         }
533     }
534 
parseGroupType( String valueString, String parent, String name, Resources resources)535     private static int parseGroupType(
536             String valueString, String parent, String name, Resources resources)
537             throws ParseException {
538         String valueToParse = getValueToParse(valueString, parent, name, resources);
539         switch (valueToParse) {
540             case ENUM_GROUP_TYPE_STATEFUL:
541                 return SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATEFUL;
542             case ENUM_GROUP_TYPE_STATELESS:
543                 return SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_STATELESS;
544             case ENUM_GROUP_TYPE_HIDDEN:
545                 return SafetySourcesGroup.SAFETY_SOURCES_GROUP_TYPE_HIDDEN;
546             default:
547                 throw attributeInvalid(valueToParse, parent, name);
548         }
549     }
550 
parseProfile( String valueString, String parent, String name, Resources resources)551     private static int parseProfile(
552             String valueString, String parent, String name, Resources resources)
553             throws ParseException {
554         String valueToParse = getValueToParse(valueString, parent, name, resources);
555         switch (valueToParse) {
556             case ENUM_PROFILE_PRIMARY:
557                 return SafetySource.PROFILE_PRIMARY;
558             case ENUM_PROFILE_ALL:
559                 return SafetySource.PROFILE_ALL;
560             default:
561                 throw attributeInvalid(valueToParse, parent, name);
562         }
563     }
564 
parseInitialDisplayState( String valueString, String parent, String name, Resources resources)565     private static int parseInitialDisplayState(
566             String valueString, String parent, String name, Resources resources)
567             throws ParseException {
568         String valueToParse = getValueToParse(valueString, parent, name, resources);
569         switch (valueToParse) {
570             case ENUM_INITIAL_DISPLAY_STATE_ENABLED:
571                 return SafetySource.INITIAL_DISPLAY_STATE_ENABLED;
572             case ENUM_INITIAL_DISPLAY_STATE_DISABLED:
573                 return SafetySource.INITIAL_DISPLAY_STATE_DISABLED;
574             case ENUM_INITIAL_DISPLAY_STATE_HIDDEN:
575                 return SafetySource.INITIAL_DISPLAY_STATE_HIDDEN;
576             default:
577                 throw attributeInvalid(valueToParse, parent, name);
578         }
579     }
580 
getValueToParse( String valueString, String parent, String name, Resources resources)581     private static String getValueToParse(
582             String valueString, String parent, String name, Resources resources) {
583         try {
584             int id = parseStringResourceName(valueString, parent, name, resources);
585             return resources.getString(id);
586         } catch (ParseException e) {
587             return valueString;
588         }
589     }
590 }
591