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 
17 package com.android.car;
18 
19 import static android.car.builtin.view.DisplayHelper.INVALID_PORT;
20 import static android.car.drivingstate.CarUxRestrictionsConfiguration.Builder.SpeedRange.MAX_SPEED;
21 import static android.car.drivingstate.CarUxRestrictionsManager.UX_RESTRICTION_MODE_BASELINE;
22 
23 import android.annotation.Nullable;
24 import android.annotation.XmlRes;
25 import android.car.CarOccupantZoneManager;
26 import android.car.builtin.util.Slogf;
27 import android.car.drivingstate.CarDrivingStateEvent;
28 import android.car.drivingstate.CarUxRestrictions;
29 import android.car.drivingstate.CarUxRestrictionsConfiguration;
30 import android.car.drivingstate.CarUxRestrictionsConfiguration.DrivingStateRestrictions;
31 import android.content.Context;
32 import android.content.res.XmlResourceParser;
33 import android.util.Log;
34 
35 import org.xmlpull.v1.XmlPullParserException;
36 
37 import java.io.IOException;
38 import java.util.ArrayList;
39 import java.util.List;
40 import java.util.Locale;
41 
42 /**
43  * @hide
44  */
45 public final class CarUxRestrictionsConfigurationXmlParser {
46     private static final String TAG = CarLog.tagFor(CarUxRestrictionsConfigurationXmlParser.class);
47     private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG);
48     private static final int UX_RESTRICTIONS_UNKNOWN = -1;
49     private static final float INVALID_SPEED = -1f;
50     private static final String XML_NAMESPACE = null;
51 
52     // XML tags
53     private static final String XML_ROOT_ELEMENT = "UxRestrictions";
54     private static final String XML_RESTRICTION_MAPPING = "RestrictionMapping";
55     private static final String XML_RESTRICTION_PARAMETERS = "RestrictionParameters";
56     private static final String XML_DRIVING_STATE = "DrivingState";
57     private static final String XML_RESTRICTIONS = "Restrictions";
58     private static final String XML_STRING_RESTRICTIONS = "StringRestrictions";
59     private static final String XML_CONTENT_RESTRICTIONS = "ContentRestrictions";
60 
61     // XML attributes
62     private static final String XML_PHYSICAL_PORT = "physicalPort";
63     private static final String XML_OCCUPANT_ZONE_ID = "occupantZoneId";
64     private static final String XML_DISPLAY_TYPE = "displayType";
65 
66     private static final String XML_STATE = "state";
67     private static final String XML_MIN_SPEED = "minSpeed";
68     private static final String XML_MAX_SPEED = "maxSpeed";
69     private static final String XML_MODE = "mode";
70     private static final String XML_UXR = "uxr";
71     private static final String XML_REQUIRES_DISTRACTION_OPTIMIZATION =
72             "requiresDistractionOptimization";
73     private static final String XML_MAX_LENGTH = "maxLength";
74     private static final String XML_MAX_CUMULATIVE_ITEMS = "maxCumulativeItems";
75     private static final String XML_MAX_DEPTH = "maxDepth";
76 
77     // XML attribute values
78     private static final String XML_STATE_PARKED = "parked";
79     private static final String XML_STATE_IDLING = "idling";
80     private static final String XML_STATE_MOVING = "moving";
81     private static final String XML_UXR_BASELINE = "baseline";
82     private static final String XML_UXR_NO_DIALPAD = "no_dialpad";
83     private static final String XML_UXR_NO_FILTERING = "no_filtering";
84     private static final String XML_UXR_LIMIT_STRING_LENGTH = "limit_string_length";
85     private static final String XML_UXR_NO_KEYBOARD = "no_keyboard";
86     private static final String XML_UXR_NO_VIDEO = "no_video";
87     private static final String XML_UXR_LIMIT_CONTENT = "limit_content";
88     private static final String XML_UXR_NO_SETUP = "no_setup";
89     private static final String XML_UXR_NO_TEXT_MESSAGE = "no_text_message";
90     private static final String XML_UXR_NO_VOICE_TRANSCRIPTION = "no_voice_transcription";
91     private static final String XML_UXR_FULLY_RESTRICTED = "fully_restricted";
92 
93     private final Context mContext;
94 
95     private int mGlobalMaxRestrictedStringLength = UX_RESTRICTIONS_UNKNOWN;
96     private int mGlobalMaxCumulativeContentItems = UX_RESTRICTIONS_UNKNOWN;
97     private int mGlobalMaxContentDepth = UX_RESTRICTIONS_UNKNOWN;
98     private final List<CarUxRestrictionsConfiguration.Builder> mConfigBuilders = new ArrayList<>();
99 
CarUxRestrictionsConfigurationXmlParser(Context context)100     private CarUxRestrictionsConfigurationXmlParser(Context context) {
101         mContext = context;
102     }
103 
104     /**
105      * Loads the UX restrictions related information from the XML resource.
106      *
107      * @return parsed CarUxRestrictionsConfiguration; {@code null} if the XML is malformed.
108      */
109     @Nullable
parse( Context context, @XmlRes int xmlResource)110     public static List<CarUxRestrictionsConfiguration> parse(
111             Context context, @XmlRes int xmlResource)
112             throws IOException, XmlPullParserException {
113         return new CarUxRestrictionsConfigurationXmlParser(context).parse(xmlResource);
114     }
115 
116     @Nullable
parse(@mlRes int xmlResource)117     private List<CarUxRestrictionsConfiguration> parse(@XmlRes int xmlResource)
118             throws IOException, XmlPullParserException {
119 
120         XmlResourceParser parser = mContext.getResources().getXml(xmlResource);
121         if (parser == null) {
122             Slogf.e(TAG, "Invalid Xml resource");
123             return null;
124         }
125 
126         if (!traverseUntilStartTag(parser)) {
127             Slogf.e(TAG, "XML root element invalid: " + parser.getName());
128             return null;
129         }
130 
131         if (!traverseUntilEndOfDocument(parser)) {
132             Slogf.e(TAG, "Could not parse XML to end");
133             return null;
134         }
135 
136         List<CarUxRestrictionsConfiguration> configs = new ArrayList<>();
137         for (int i = 0, length = mConfigBuilders.size(); i < length; i++) {
138             CarUxRestrictionsConfiguration.Builder builder = mConfigBuilders.get(i);
139             builder.setMaxStringLengthIfNotSet(mGlobalMaxRestrictedStringLength)
140                     .setMaxCumulativeContentItemsIfNotSet(mGlobalMaxCumulativeContentItems)
141                     .setMaxContentDepthIfNotSet(mGlobalMaxContentDepth);
142             configs.add(builder.build());
143         }
144         return configs;
145     }
146 
traverseUntilStartTag(XmlResourceParser parser)147     private boolean traverseUntilStartTag(XmlResourceParser parser)
148             throws IOException, XmlPullParserException {
149         int type;
150         // Traverse till the first tag is hit
151         while ((type = parser.next()) != XmlResourceParser.END_DOCUMENT
152                 && type != XmlResourceParser.START_TAG) {
153             // Do nothing.
154         }
155         return XML_ROOT_ELEMENT.equals(parser.getName());
156     }
157 
traverseUntilEndOfDocument(XmlResourceParser parser)158     private boolean traverseUntilEndOfDocument(XmlResourceParser parser)
159             throws XmlPullParserException, IOException {
160         while (parser.getEventType() != XmlResourceParser.END_DOCUMENT) {
161             // Every time a start tag is hit, check for the type of the tag
162             // and load the corresponding information.
163             if (parser.next() == XmlResourceParser.START_TAG) {
164                 switch (parser.getName()) {
165                     case XML_RESTRICTION_MAPPING:
166                         // Each RestrictionMapping tag represents a new set of rules.
167                         CarUxRestrictionsConfiguration.Builder builder =
168                                 new CarUxRestrictionsConfiguration.Builder();
169                         mConfigBuilders.add(builder);
170 
171                         if (!mapDrivingStateToRestrictions(parser)) {
172                             Slogf.e(TAG, "Could not map driving state to restriction.");
173                             return false;
174                         }
175                         parseLocalRestrictionParameters(parser, builder);
176                         break;
177                     case XML_RESTRICTION_PARAMETERS:
178                         if (!parseGlobalRestrictionParameters(parser)) {
179                             // Failure to parse is automatically handled by falling back to
180                             // defaults. Just log the information here.
181                             Slogf.w(TAG, "Error reading restrictions parameters. "
182                                     + "Falling back to platform defaults.");
183                         }
184                         break;
185                     default:
186                         Slogf.w(TAG, "Unknown class:" + parser.getName());
187                 }
188             }
189         }
190         return true;
191     }
192 
193     /**
194      * Parses the information in the local {@code RestrictionParameters} within a
195      * {@code RestrictionMapping} container tag to read the parameters for the applicable UX
196      * restrictions.
197      */
parseLocalRestrictionParameters(XmlResourceParser parser, CarUxRestrictionsConfiguration.Builder builder)198     private void parseLocalRestrictionParameters(XmlResourceParser parser,
199             CarUxRestrictionsConfiguration.Builder builder)
200             throws IOException, XmlPullParserException {
201         if (parser == null) {
202             Slogf.e(TAG, "Parser is null");
203             return;
204         }
205 
206         if (XML_RESTRICTION_MAPPING.equals(parser.getName())) {
207             if (DBG) {
208                 Slogf.d(TAG,
209                         "No local restriction parameters for this, the global restriction "
210                                 + "parameters will be used");
211             }
212             return;
213         }
214         if (!XML_RESTRICTION_PARAMETERS.equals(parser.getName())) {
215             if (DBG) {
216                 Slogf.d(TAG,
217                         "Unsupported Restriction Parameters in XML: %s, the global restriction "
218                                 + "parameters will be used", parser.getName());
219             }
220             return;
221         }
222         parseRestrictionParameters(parser, builder);
223     }
224 
parseRestrictionParameters(XmlResourceParser parser, @Nullable CarUxRestrictionsConfiguration.Builder builder)225     private void parseRestrictionParameters(XmlResourceParser parser,
226             @Nullable CarUxRestrictionsConfiguration.Builder builder)
227             throws IOException, XmlPullParserException {
228         while (parser.getEventType() != XmlResourceParser.END_DOCUMENT) {
229             int type = parser.next();
230             // Break if all <RestrictionParameters> are parsed
231             if (type == XmlResourceParser.END_TAG && XML_RESTRICTION_PARAMETERS.equals(
232                     parser.getName())) {
233                 return;
234             }
235 
236             if (type == XmlResourceParser.START_TAG) {
237                 switch (parser.getName()) {
238                     case XML_STRING_RESTRICTIONS:
239                         setStringRestrictionParameters(builder, parser);
240                         break;
241                     case XML_CONTENT_RESTRICTIONS:
242                         setContentRestrictionParameters(builder, parser);
243                         break;
244                     default:
245                         Slogf.i(TAG, "Unsupported Restriction Parameters in XML: %s",
246                                 parser.getName());
247                         break;
248                 }
249             }
250         }
251     }
252 
253     /**
254      * Adds string restriction parameters to the {@link CarUxRestrictionsConfiguration.Builder}
255      * object.
256      */
setStringRestrictionParameters(CarUxRestrictionsConfiguration.Builder builder, XmlResourceParser parser)257     private void setStringRestrictionParameters(CarUxRestrictionsConfiguration.Builder builder,
258             XmlResourceParser parser) {
259         int maxRestrictedStringLength = parser.getAttributeIntValue(XML_NAMESPACE, XML_MAX_LENGTH,
260                 UX_RESTRICTIONS_UNKNOWN);
261         if (builder != null) {
262             builder.setMaxStringLengthIfNotSet(maxRestrictedStringLength);
263         } else {
264             mGlobalMaxRestrictedStringLength = maxRestrictedStringLength;
265         }
266     }
267 
268     /**
269      * Adds content restriction parameters to the {@link CarUxRestrictionsConfiguration.Builder}
270      * object.
271      */
setContentRestrictionParameters(CarUxRestrictionsConfiguration.Builder builder, XmlResourceParser parser)272     private void setContentRestrictionParameters(CarUxRestrictionsConfiguration.Builder builder,
273             XmlResourceParser parser) {
274         int maxCumulativeContentItems = parser.getAttributeIntValue(XML_NAMESPACE,
275                 XML_MAX_CUMULATIVE_ITEMS, UX_RESTRICTIONS_UNKNOWN);
276         int maxContentDepth = parser.getAttributeIntValue(XML_NAMESPACE, XML_MAX_DEPTH,
277                 UX_RESTRICTIONS_UNKNOWN);
278         if (builder != null) {
279             // Set local restriction parameters
280             builder.setMaxContentDepthIfNotSet(maxContentDepth);
281             builder.setMaxCumulativeContentItemsIfNotSet(maxCumulativeContentItems);
282         } else {
283             // Set global restriction parameters
284             mGlobalMaxCumulativeContentItems = maxCumulativeContentItems;
285             mGlobalMaxContentDepth = maxContentDepth;
286         }
287     }
288 
289     /**
290      * Parses the information in the <restrictionMapping> tag to construct the mapping from
291      * driving state to UX restrictions.
292      */
mapDrivingStateToRestrictions(XmlResourceParser parser)293     private boolean mapDrivingStateToRestrictions(XmlResourceParser parser)
294             throws IOException, XmlPullParserException {
295         if (parser == null) {
296             Slogf.e(TAG, "Invalid arguments");
297             return false;
298         }
299         // The parser should be at the <RestrictionMapping> tag at this point.
300         if (!XML_RESTRICTION_MAPPING.equals(parser.getName())) {
301             Slogf.e(TAG, "Parser not at RestrictionMapping element: " + parser.getName());
302             return false;
303         }
304         // read port
305         int portValue = parser.getAttributeIntValue(XML_NAMESPACE, XML_PHYSICAL_PORT,
306                 INVALID_PORT);
307         if (portValue != INVALID_PORT) {
308             int port = CarUxRestrictionsConfiguration.Builder.validatePort(portValue);
309             getCurrentBuilder().setPhysicalPort(port);
310         }
311 
312         // read occupant zone id
313         int zoneIdValue = parser.getAttributeIntValue(XML_NAMESPACE, XML_OCCUPANT_ZONE_ID,
314                 CarOccupantZoneManager.OccupantZoneInfo.INVALID_ZONE_ID);
315         if (zoneIdValue != CarOccupantZoneManager.OccupantZoneInfo.INVALID_ZONE_ID) {
316             int zoneId = CarUxRestrictionsConfiguration.Builder.validateOccupantZoneId(zoneIdValue);
317             getCurrentBuilder().setOccupantZoneId(zoneId);
318         }
319 
320         // read occupant zone id
321         int displayTypeValue = parser.getAttributeIntValue(XML_NAMESPACE, XML_DISPLAY_TYPE,
322                 CarOccupantZoneManager.DISPLAY_TYPE_UNKNOWN);
323         if (displayTypeValue != CarOccupantZoneManager.DISPLAY_TYPE_UNKNOWN) {
324             int displayType = CarUxRestrictionsConfiguration.Builder.validateDisplayType(
325                     displayTypeValue);
326             getCurrentBuilder().setDisplayType(displayType);
327         }
328 
329         if (!traverseToTag(parser, XML_DRIVING_STATE)) {
330             Slogf.e(TAG, "No <" + XML_DRIVING_STATE + "> tag in XML");
331             return false;
332         }
333         // Handle all the <DrivingState> tags.
334         while (XML_DRIVING_STATE.equals(parser.getName())) {
335             if (parser.getEventType() == XmlResourceParser.START_TAG) {
336                 // 1. Get the driving state attributes: driving state and speed range
337                 int drivingState = getDrivingState(
338                         parser.getAttributeValue(XML_NAMESPACE, XML_STATE));
339                 float minSpeed = 0;
340                 try {
341                     minSpeed = Float
342                             .parseFloat(parser.getAttributeValue(XML_NAMESPACE, XML_MIN_SPEED));
343                 } catch (NullPointerException | NumberFormatException e) {
344                     minSpeed = INVALID_SPEED;
345                 }
346 
347                 float maxSpeed = 0;
348                 try {
349                     maxSpeed = Float
350                             .parseFloat(parser.getAttributeValue(XML_NAMESPACE, XML_MAX_SPEED));
351                 } catch (NullPointerException | NumberFormatException e) {
352                     maxSpeed = MAX_SPEED;
353                 }
354 
355                 // 2. Traverse to the <Restrictions> tag
356                 if (!traverseToTag(parser, XML_RESTRICTIONS)) {
357                     Slogf.e(TAG, "No <" + XML_RESTRICTIONS + "> tag in XML");
358                     return false;
359                 }
360 
361                 // 3. Parse the restrictions for this driving state
362                 CarUxRestrictionsConfiguration.Builder.SpeedRange speedRange = parseSpeedRange(
363                         minSpeed, maxSpeed);
364                 if (!parseAllRestrictions(parser, drivingState, speedRange)) {
365                     Slogf.e(TAG, "Could not parse restrictions for driving state:" + drivingState);
366                     return false;
367                 }
368             }
369             parser.next();
370         }
371         return true;
372     }
373 
getDrivingState(String state)374     private int getDrivingState(String state) {
375         if (state == null) {
376             return CarDrivingStateEvent.DRIVING_STATE_UNKNOWN;
377         }
378 
379         switch (state.trim().toLowerCase(Locale.ROOT)) {
380             case XML_STATE_PARKED:
381                 return CarDrivingStateEvent.DRIVING_STATE_PARKED;
382             case XML_STATE_IDLING:
383                 return CarDrivingStateEvent.DRIVING_STATE_IDLING;
384             case XML_STATE_MOVING:
385                 return CarDrivingStateEvent.DRIVING_STATE_MOVING;
386             default:
387                 return CarDrivingStateEvent.DRIVING_STATE_UNKNOWN;
388         }
389     }
390 
391     /**
392      * Parses all <restrictions> tags nested with <drivingState> tag.
393      */
parseAllRestrictions(XmlResourceParser parser, int drivingState, CarUxRestrictionsConfiguration.Builder.SpeedRange speedRange)394     private boolean parseAllRestrictions(XmlResourceParser parser,
395             int drivingState, CarUxRestrictionsConfiguration.Builder.SpeedRange speedRange)
396             throws IOException, XmlPullParserException {
397         if (parser == null) {
398             Slogf.e(TAG, "Invalid arguments");
399             return false;
400         }
401         // The parser should be at the <Restrictions> tag at this point.
402         if (!XML_RESTRICTIONS.equals(parser.getName())) {
403             Slogf.e(TAG, "Parser not at Restrictions element: " + parser.getName());
404             return false;
405         }
406         while (XML_RESTRICTIONS.equals(parser.getName())) {
407             if (parser.getEventType() == XmlResourceParser.START_TAG) {
408                 // Parse one restrictions tag.
409                 List<DrivingStateRestrictions> restrictions = parseRestrictions(parser);
410                 if (restrictions == null || restrictions.isEmpty()) {
411                     Slogf.e(TAG, "");
412                     return false;
413                 }
414                 // Update the builder if the driving state and restrictions info are valid.
415                 if (drivingState != CarDrivingStateEvent.DRIVING_STATE_UNKNOWN
416                         && restrictions != null) {
417                     for (int i = 0; i < restrictions.size(); i++) {
418                         DrivingStateRestrictions restriction = restrictions.get(i);
419                         restriction.setSpeedRange(speedRange);
420 
421                         if (DBG) {
422                             Slogf.d(TAG, "Map " + drivingState + " : " + restriction);
423                         }
424                         getCurrentBuilder().setUxRestrictions(drivingState, restriction);
425                     }
426                 }
427             }
428             parser.next();
429         }
430         return true;
431     }
432 
433     /**
434      * Parses the <restrictions> tag nested with the <drivingState>.  This provides the restrictions
435      * for the enclosing driving state.
436      *
437      * @return Driving state restrictions list. The list would contain more than one value if mode
438      * attribute defines more than one mode separated by "|".
439      */
440     @Nullable
parseRestrictions(XmlResourceParser parser)441     private List<DrivingStateRestrictions> parseRestrictions(XmlResourceParser parser)
442             throws IOException, XmlPullParserException {
443         if (parser == null) {
444             Slogf.e(TAG, "Invalid Arguments");
445             return null;
446         }
447 
448         int restrictions = UX_RESTRICTIONS_UNKNOWN;
449         List<String> restrictionModes =  new ArrayList<>();
450         boolean requiresOpt = true;
451         if (XML_RESTRICTIONS.equals(parser.getName())
452                 && parser.getEventType() == XmlResourceParser.START_TAG) {
453             restrictions = getRestrictions(parser.getAttributeValue(XML_NAMESPACE, XML_UXR));
454             updateModes(parser.getAttributeValue(XML_NAMESPACE, XML_MODE), restrictionModes);
455             requiresOpt = parser.getAttributeBooleanValue(XML_NAMESPACE,
456                     XML_REQUIRES_DISTRACTION_OPTIMIZATION, true);
457             parser.next();
458         }
459 
460         List<DrivingStateRestrictions> drivingStateRestrictions = new ArrayList<>();
461 
462         for (int i = 0; i < restrictionModes.size(); i++) {
463             drivingStateRestrictions.add(new DrivingStateRestrictions()
464                     .setDistractionOptimizationRequired(requiresOpt)
465                     .setRestrictions(restrictions)
466                     .setMode(restrictionModes.get(i)));
467         }
468 
469         return drivingStateRestrictions;
470     }
471 
updateModes(String allModes, List<String> modes)472     private void updateModes(String allModes, List<String> modes) {
473         if (allModes == null) {
474             modes.add(UX_RESTRICTION_MODE_BASELINE);
475             return;
476         }
477         String[] allModesArray = allModes.split("\\|");
478 
479         for (int i = 0; i < allModesArray.length; i++) {
480             modes.add(allModesArray[i].trim());
481         }
482     }
483 
getRestrictions(String allRestrictions)484     private int getRestrictions(String allRestrictions) {
485         if (allRestrictions == null) {
486             return CarUxRestrictions.UX_RESTRICTIONS_FULLY_RESTRICTED;
487         }
488         int restrictionsValue = 0;
489         String[] restrictions = allRestrictions.split("\\|");
490         for (int i = 0; i < restrictions.length; i++) {
491             String restriction = restrictions[i].trim().toLowerCase(Locale.ROOT);
492             switch (restriction) {
493                 case XML_UXR_BASELINE:
494                     restrictionsValue = restrictionsValue
495                             | CarUxRestrictions.UX_RESTRICTIONS_BASELINE;
496                     break;
497                 case XML_UXR_NO_DIALPAD:
498                     restrictionsValue = restrictionsValue
499                             | CarUxRestrictions.UX_RESTRICTIONS_NO_DIALPAD;
500                     break;
501                 case XML_UXR_NO_FILTERING:
502                     restrictionsValue = restrictionsValue
503                             | CarUxRestrictions.UX_RESTRICTIONS_NO_FILTERING;
504                     break;
505                 case XML_UXR_LIMIT_STRING_LENGTH:
506                     restrictionsValue = restrictionsValue
507                             | CarUxRestrictions.UX_RESTRICTIONS_LIMIT_STRING_LENGTH;
508                     break;
509                 case XML_UXR_NO_KEYBOARD:
510                     restrictionsValue = restrictionsValue
511                             | CarUxRestrictions.UX_RESTRICTIONS_NO_KEYBOARD;
512                     break;
513                 case XML_UXR_NO_VIDEO:
514                     restrictionsValue = restrictionsValue
515                             | CarUxRestrictions.UX_RESTRICTIONS_NO_VIDEO;
516                     break;
517                 case XML_UXR_LIMIT_CONTENT:
518                     restrictionsValue = restrictionsValue
519                             | CarUxRestrictions.UX_RESTRICTIONS_LIMIT_CONTENT;
520                     break;
521                 case XML_UXR_NO_SETUP:
522                     restrictionsValue = restrictionsValue
523                             | CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP;
524                     break;
525                 case XML_UXR_NO_TEXT_MESSAGE:
526                     restrictionsValue = restrictionsValue
527                             | CarUxRestrictions.UX_RESTRICTIONS_NO_TEXT_MESSAGE;
528                     break;
529                 case XML_UXR_NO_VOICE_TRANSCRIPTION:
530                     restrictionsValue = restrictionsValue
531                             | CarUxRestrictions.UX_RESTRICTIONS_NO_VOICE_TRANSCRIPTION;
532                     break;
533                 case XML_UXR_FULLY_RESTRICTED:
534                     restrictionsValue = restrictionsValue
535                             | CarUxRestrictions.UX_RESTRICTIONS_FULLY_RESTRICTED;
536                     break;
537                 default:
538                     break;
539             }
540         }
541         return restrictionsValue;
542     }
543 
544     @Nullable
parseSpeedRange(float minSpeed, float maxSpeed)545     private CarUxRestrictionsConfiguration.Builder.SpeedRange parseSpeedRange(float minSpeed,
546                                                                               float maxSpeed) {
547         if (Float.compare(minSpeed, 0) < 0 || Float.compare(maxSpeed, 0) < 0) {
548             return null;
549         }
550         return new CarUxRestrictionsConfiguration.Builder.SpeedRange(minSpeed, maxSpeed);
551     }
552 
traverseToTag(XmlResourceParser parser, String tag)553     private boolean traverseToTag(XmlResourceParser parser, String tag)
554             throws IOException, XmlPullParserException {
555         if (tag == null || parser == null) {
556             return false;
557         }
558         int type;
559         while ((type = parser.next()) != XmlResourceParser.END_DOCUMENT) {
560             if (type == XmlResourceParser.START_TAG && parser.getName().equals(tag)) {
561                 return true;
562             }
563         }
564         return false;
565     }
566 
567     /**
568      * Parses the information in the global {@code RestrictionParameters} in a
569      * {@code UxRestrictions} tag to read the parameters for the applicable UX restrictions.
570      */
parseGlobalRestrictionParameters(XmlResourceParser parser)571     private boolean parseGlobalRestrictionParameters(XmlResourceParser parser)
572             throws IOException, XmlPullParserException {
573         if (parser == null) {
574             Slogf.e(TAG, "Parser is null");
575             return false;
576         }
577         // The parser should be at the <RestrictionParameters> tag at this point.
578         if (!XML_RESTRICTION_PARAMETERS.equals(parser.getName())) {
579             Slogf.e(TAG, "Parser not at RestrictionParameters element: %s", parser.getName());
580             return false;
581         }
582         parseRestrictionParameters(parser, null);
583         return true;
584     }
585 
getCurrentBuilder()586     private CarUxRestrictionsConfiguration.Builder getCurrentBuilder() {
587         return mConfigBuilders.get(mConfigBuilders.size() - 1);
588     }
589 }
590