• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.phone;
18 
19 import android.content.Context;
20 import android.content.res.XmlResourceParser;
21 import android.support.annotation.VisibleForTesting;
22 import android.telephony.TelephonyManager;
23 import android.text.TextUtils;
24 import android.util.Log;
25 
26 import org.xmlpull.v1.XmlPullParser;
27 import org.xmlpull.v1.XmlPullParserException;
28 
29 import java.io.IOException;
30 import java.util.ArrayList;
31 import java.util.HashMap;
32 import java.util.Map;
33 import java.util.Vector;
34 import java.util.regex.Matcher;
35 import java.util.regex.Pattern;
36 
37 /**
38  * CarrierXmlParser is a xml parser. It parses the carrier's ussd format from carrier_ss_string.xml.
39  * The carrier_ss_string.xml defines carrier's ussd structure and meaning in res/xml folder.
40  * Some carrier has specific ussd structure ,developer can add new xml and xml is named
41  * carrier_ss_string_carrierId.xml. The carrierId is a number and is defined in
42  * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a>
43  * For example: carrier_ss_string_850.xml
44  * <p>
45  * How do use CarrierXmlParser?
46  * For example:
47  * @see CallForwardEditPreference
48  *     TelephonyManager telephonyManager = new TelephonyManager(getContext(),phone.getSubId());
49  *     CarrierXmlParser  = new CarrierXmlParser(getContext(), telephonyManager.getSimCarrierId());
50  *
51  *     //make a ussd command
52  *     String newUssdCommand = mCarrierXmlParser.getFeature(
53  *             CarrierXmlParser.FEATURE_CALL_FORWARDING).makeCommand(inputAction, inputCfInfo);
54  *     //analyze ussd result
55  *     HashMap<String, String> analysisResult = mCarrierXmlParser.getFeature(
56  *             CarrierXmlParser.FEATURE_CALL_FORWARDING)
57  *             .getResponseSet(mSsAction, response.toString());
58  */
59 public class CarrierXmlParser {
60     public static final String LOG_TAG = "CarrierXmlParser";
61     private static final boolean DEBUG = true;
62 
63     private static final String STAR_SIGN = "*";
64     private static final String POUND_SIGN = "#";
65 
66     private static final String TAG_SIGN = "tag_";
67 
68     // To define feature's item name in xml
69     public static final String FEATURE_CALL_FORWARDING = "callforwarding";
70     public static final String FEATURE_CALL_WAITING = "callwaiting";
71     public static final String FEATURE_CALLER_ID = "callerid";
72 
73     // COMMAND_NAME is xml's command name.
74     public static final String TAG_COMMAND_NAME_QUERY = "query";
75     public static final String TAG_COMMAND_NAME_ACTIVATE = "activate";
76     public static final String TAG_COMMAND_NAME_DEACTIVATE = "deactivate";
77 
78     // To define string level in xml.
79     // level 1
80     private static final String TAG_FEATURE = "feature";
81     private static final String TAG_REGULAR_PARSER = "regular_parser";
82     // level 2
83     private static final String TAG_COMMAND = "command";
84     // level 3
85     private static final String TAG_SERVICE_CODE = "service_code";
86     private static final String TAG_ACTION_CODE = "action_code";
87     private static final String TAG_PARAMETER = "parameter";
88     private static final String TAG_RESPONSE_FORMAT = "response_format";
89     private static final String TAG_COMMAND_RESULT = "command_result";
90     // level 4
91     private static final String TAG_ENTRY = "entry";
92 
93     private static final String ATTR_NAME = "name";
94     private static final String ATTR_PARAMETER_NUM = "number";
95     private static final String ATTR_POSITION = "position";
96     private static final String ATTR_RESULT_KEY = "key";
97     private static final String ATTR_DEFINITION_KEY = "definition";
98 
99     HashMap<String, SsFeature> mFeatureMaps;
100 
101     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
102     static String sParserFormat = "";
103 
104     // TAG_ENTRY_NUMBER and TAG_ENTRY_TIME is xml's entry value.
105     // This is mapping user's input value. For example: number,time ...
106     // When UI makes command ,it will map the value and insert this value at position location.
107     // How to use it?
108     //      The UI calls CarrierXmlParser's makeCommand function and inputs the hashmap which
109     //      includes tag_name and user's input value.
110     //      For example: User calls CarrierXmlParser's makeCommand in call forwarding , and inputs
111     //      the hashmap {<TAG_ENTRY_NUMBER,0123456789>,<TAG_ENTRY_TIME,20>}
112     // If developer wants to add new one, xml string should the same as hashmap's name.
113     public static final String TAG_ENTRY_NUMBER = "tag_number";
114     public static final String TAG_ENTRY_TIME = "tag_time";
115 
116     // "response_format" key
117     // The key of "response_format" should define as below in xml.
118     // The UI will use it to define value from the response command
119     // and use the data show the screen.
120     public static final String TAG_RESPONSE_STATUS = "status_code";
121     public static final String TAG_RESPONSE_STATUS_ERROR = "RESPONSE_ERROR";
122     public static final String TAG_RESPONSE_NUMBER = "number";
123     public static final String TAG_RESPONSE_TIME = "time";
124 
125     // This is the definition for the entry's key in response_format.
126     // Xml's COMMAND_RESULT_DEFINITION should same as below.
127     public static final String TAG_COMMAND_RESULT_DEFINITION_ACTIVATE = "activate";
128     public static final String TAG_COMMAND_RESULT_DEFINITION_DEACTIVATE = "deactivate";
129     public static final String TAG_COMMAND_RESULT_DEFINITION_UNREGISTER = "unregister";
130     public static final String TAG_COMMAND_RESULT_DEFINITION_OK = "ok";
131     public static final String TAG_COMMAND_RESULT_DEFINITION_FAIL = "fail";
132 
133     /**
134      * UssdParser is a string parser. It parses the USSD response message.
135      */
136     public static class UssdParser {
137         private Vector<String> mParserStr = new Vector<String>();
138         private Pattern mPatternSuppServiceResponse;
139 
UssdParser(String inputParserFormat)140         public UssdParser(String inputParserFormat) {
141             mPatternSuppServiceResponse = Pattern.compile(inputParserFormat);
142         }
143 
144         /**
145          * This function is a parser and analyzes the USSD responses message.
146          *
147          * @param responseString The USSD responses message.
148          */
newFromResponseString(String responseString)149         public void newFromResponseString(String responseString) {
150             Matcher m;
151             m = mPatternSuppServiceResponse.matcher(responseString);
152             if (m.matches()) {
153                 mParserStr.clear();
154                 int groupSize = m.groupCount();
155                 for (int i = 0; i <= groupSize; i++) {
156                     if (!TextUtils.isEmpty(m.group(i))) {
157                         mParserStr.add(m.group(i));
158                     } else {
159                         mParserStr.add("");
160                     }
161                 }
162             } else {
163                 Log.d(LOG_TAG, "no match");
164             }
165         }
166 
167         /**
168          * To get the UssdParser result.
169          */
getResult()170         public Vector<String> getResult() {
171             return mParserStr;
172         }
173     }
174 
175     /**
176      * CarrierXmlParser parses command from xml and saves in SsEntry class.
177      */
178     public static class SsEntry {
179         public enum SSAction {
180             UNKNOWN,
181             QUERY,
182             UPDATE_ACTIVATE,
183             UPDATE_DEACTIVATE
184         }
185 
186         public String serviceCode;
187         public SSAction ssAction = SSAction.UNKNOWN;
188         public String actionCode;
189         public HashMap<Integer, String> commandParameter = new HashMap<Integer, String>();
190         public HashMap<Integer, String> responseFormat = new HashMap<Integer, String>();
191 
SsEntry(String action)192         public SsEntry(String action) {
193             if (action.equals(TAG_COMMAND_NAME_QUERY)) {
194                 ssAction = SSAction.QUERY;
195             } else if (action.equals(TAG_COMMAND_NAME_ACTIVATE)) {
196                 ssAction = SSAction.UPDATE_ACTIVATE;
197             } else if (action.equals(TAG_COMMAND_NAME_DEACTIVATE)) {
198                 ssAction = SSAction.UPDATE_DEACTIVATE;
199             }
200         }
201 
202         @Override
toString()203         public String toString() {
204             return "SsEntry serviceCode:" + serviceCode
205                     + ", ssAction:" + ssAction
206                     + ", actionCode:" + actionCode
207                     + ", commandParameter:" + commandParameter.toString()
208                     + ", responseFormat:" + responseFormat.toString();
209         }
210 
211         /**
212          * To get the caller id command by xml's structure.
213          */
getCommandStructure()214         public String getCommandStructure() {
215             String result = actionCode + serviceCode;
216             int mapSize = commandParameter.size();
217             int parameterIndex = 0;
218             while (parameterIndex < mapSize) {
219                 parameterIndex++;
220                 if (commandParameter.containsKey(parameterIndex)) {
221                     if (commandParameter.get(parameterIndex) != null) {
222                         result = result + STAR_SIGN + commandParameter.get(parameterIndex);
223                     }
224                 }
225             }
226             result = result + POUND_SIGN;
227             Log.d(LOG_TAG, "getCommandStructure result:" + result);
228             return result;
229         }
230 
231         /**
232          * To make ussd command by xml's structure.
233          *
234          * @param inputInformationSet This is a map which includes parameters from UI.
235          *                            The name of map is mapping parameter's key of entry in xml.
236          */
makeCommand(Map<String, String> inputInformationSet)237         public String makeCommand(Map<String, String> inputInformationSet) {
238             String result = actionCode + serviceCode;
239             int mapSize = commandParameter.size();
240             int parameterIndex = 0;
241             int counter = 1;
242             Map<String, String> informationSet = inputInformationSet;
243             while (parameterIndex < mapSize) {
244                 if (commandParameter.containsKey(counter)) {
245                     String getInputValue = "";
246                     // need to handle tag_XXXX
247                     if (informationSet != null && informationSet.size() > 0
248                             && informationSet.containsKey(commandParameter.get(counter))) {
249                         getInputValue = informationSet.get(commandParameter.get(counter));
250                     }
251                     if (TextUtils.isEmpty(getInputValue)) {
252                         result = result + STAR_SIGN + commandParameter.get(counter);
253                     } else {
254                         result = result + STAR_SIGN + informationSet.get(
255                                 commandParameter.get(counter));
256                     }
257                     parameterIndex++;
258                 } else {
259                     result = result + STAR_SIGN;
260                 }
261                 counter++;
262             }
263             result = result + POUND_SIGN;
264             return result;
265         }
266 
267         /**
268          * To parse the specific key and value from response message.
269          *
270          * @param inputResponse  This is a ussd response message from network.
271          * @param responseDefine This is the definition for "command_result" in xml.
272          */
getResponseSet(String inputResponse, HashMap<String, ArrayList<SsResultEntry>> responseDefine)273         public HashMap<String, String> getResponseSet(String inputResponse,
274                 HashMap<String, ArrayList<SsResultEntry>> responseDefine) {
275             HashMap<String, String> responseSet = new HashMap<String, String>();
276             if (TextUtils.isEmpty(sParserFormat)) {
277                 return responseSet;
278             }
279             UssdParser parserResult = new UssdParser(sParserFormat);
280             parserResult.newFromResponseString(inputResponse);
281             if (parserResult == null) {
282                 return responseSet;
283             }
284 
285             Vector<String> result = parserResult.getResult();
286 
287             if (result == null) {
288                 return responseSet;
289             }
290             for (int i = 0; i < result.size(); i++) {
291                 if (responseFormat.containsKey(i)) {
292                     String defineString = "";
293                     if (responseDefine.containsKey(responseFormat.get(i))) {
294                         for (int x = 0; x < responseDefine.get(responseFormat.get(i)).size(); x++) {
295                             defineString = ((SsResultEntry) responseDefine.get(
296                                     responseFormat.get(i)).get(x)).getDefinitionByCompareValue(
297                                     result.get(i));
298                             if (!TextUtils.isEmpty(defineString)) {
299                                 break;
300                             }
301                         }
302                         // if status_code do not match definition value, we will set command error.
303                         if (TAG_RESPONSE_STATUS.equals(responseFormat.get(i))) {
304                             if (TextUtils.isEmpty(defineString)) {
305                                 responseSet.put(TAG_RESPONSE_STATUS_ERROR,
306                                         TAG_RESPONSE_STATUS_ERROR);
307                             }
308                         }
309                     }
310                     if (TextUtils.isEmpty(defineString)) {
311                         responseSet.put(responseFormat.get(i), result.get(i));
312                     } else {
313                         responseSet.put(responseFormat.get(i), defineString);
314                     }
315                 }
316             }
317             return responseSet;
318         }
319     }
320 
321     /**
322      * CarrierXmlParser parses command_result from xml and saves in SsResultEntry class.
323      */
324     public static class SsResultEntry {
325         String mDefinition;
326         String mCompareValue;
327 
SsResultEntry()328         public SsResultEntry() {
329         }
330 
331         @Override
toString()332         public String toString() {
333             return "SsResultEntry mDefinition:" + mDefinition
334                     + ", mCompareValue:" + mCompareValue;
335         }
336 
337         /**
338          * If mCompareValue item is the same as compare value,it will return the mDefinition.
339          *
340          * @param inputValue This is the entry of response command's value.
341          * @return mDefinition or null.
342          */
getDefinitionByCompareValue(String inputValue)343         public String getDefinitionByCompareValue(String inputValue) {
344             if (mCompareValue.equals(inputValue)) {
345                 return mDefinition;
346             }
347             return null;
348         }
349     }
350 
351     /**
352      * CarrierXmlParser parses feature from xml and saves in SsFeature class.
353      */
354     public class SsFeature {
355         public HashMap<SsEntry.SSAction, SsEntry> ssEntryHashMap =
356                 new HashMap<SsEntry.SSAction, SsEntry>();
357         public HashMap<String, ArrayList<SsResultEntry>> responseCode =
358                 new HashMap<String, ArrayList<SsResultEntry>>();
359 
SsFeature()360         public SsFeature() {
361         }
362 
getResponseCodeString()363         private String getResponseCodeString() {
364             String result = "";
365             for (Map.Entry<String, ArrayList<SsResultEntry>> entry : responseCode.entrySet()) {
366                 ArrayList<SsResultEntry> values = entry.getValue();
367                 for (int i = 0; i < values.size(); i++) {
368                     result += "value of i is " + ((SsResultEntry) values.get(i)).toString();
369                 }
370             }
371             return result;
372         }
373 
374         @Override
toString()375         public String toString() {
376             return getResponseCodeString();
377         }
378 
379         /**
380          * To get the caller id command by xml's structure.
381          *
382          * @param inputAction This is action_code of command item from xml.
383          */
getCommandStructure(SsEntry.SSAction inputAction)384         public String getCommandStructure(SsEntry.SSAction inputAction) {
385             SsEntry entry = ssEntryHashMap.get(inputAction);
386             return entry.getCommandStructure();
387         }
388 
389         /**
390          * To make the ussd command by xml structure
391          *
392          * @param inputAction         This is action_code of command item from xml.
393          * @param inputInformationSet This is for parameter of command.
394          * @return The ussd command string.
395          */
makeCommand(SsEntry.SSAction inputAction, Map<String, String> inputInformationSet)396         public String makeCommand(SsEntry.SSAction inputAction,
397                 Map<String, String> inputInformationSet) {
398             SsEntry entry = ssEntryHashMap.get(inputAction);
399             return entry.makeCommand(inputInformationSet);
400         }
401 
402         /**
403          * To parse the special key and value from response message.
404          *
405          * @param inputAction   This is action_code of command item from xml.
406          * @param inputResponse This is response message from network.
407          * @return The set includes specific key and value.
408          */
getResponseSet(SsEntry.SSAction inputAction, String inputResponse)409         public HashMap<String, String> getResponseSet(SsEntry.SSAction inputAction,
410                 String inputResponse) {
411             SsEntry entry = ssEntryHashMap.get(inputAction);
412             return entry.getResponseSet(inputResponse, responseCode);
413         }
414     }
415 
416     /**
417      * @param context context to get res's xml
418      * @param carrierId carrier id of the current subscription. The carrier ID is an Android
419      * platform-wide identifier for a carrier. AOSP maintains carrier ID assignments in
420      * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a>
421      */
CarrierXmlParser(Context context, int carrierId)422     public CarrierXmlParser(Context context, int carrierId) {
423         try {
424             int xmlResId = 0;
425             if (carrierId != TelephonyManager.UNKNOWN_CARRIER_ID) {
426                 String xmlResIdName = "carrier_ss_string" + "_" + carrierId;
427                 xmlResId = context.getResources().getIdentifier(xmlResIdName, "xml",
428                         context.getPackageName());
429             }
430             if (xmlResId == 0) {
431                 xmlResId = R.xml.carrier_ss_string;
432             }
433             Log.d(LOG_TAG, "carrierId: " + carrierId);
434 
435             XmlResourceParser parser = context.getResources().getXml(xmlResId);
436             mFeatureMaps = parseXml(parser);
437         } catch (Exception e) {
438             Log.d(LOG_TAG, "Error parsing XML " + e.toString());
439         }
440     }
441 
parseXml(XmlResourceParser parser)442     private HashMap<String, SsFeature> parseXml(XmlResourceParser parser) throws IOException {
443         HashMap<String, SsFeature> features = new HashMap<String, SsFeature>();
444         try {
445             int eventType = parser.getEventType();
446             while (eventType != XmlPullParser.END_DOCUMENT) {
447                 if (eventType == XmlPullParser.START_TAG) {
448                     if (TAG_REGULAR_PARSER.equals(parser.getName())) {
449                         sParserFormat = readText(parser);
450                         Log.d(LOG_TAG, "sParserFormat " + sParserFormat);
451                     } else if (TAG_FEATURE.equals(parser.getName())) {
452                         String featureName = getSpecificAttributeValue(parser, ATTR_NAME);
453                         if (!TextUtils.isEmpty(featureName)) {
454                             SsFeature feature = generateFeatureList(parser);
455                             features.put(featureName, feature);
456                             Log.d(LOG_TAG, "add " + featureName + " to map:" + feature.toString());
457                         }
458                     }
459                 }
460                 parser.next();
461                 eventType = parser.getEventType();
462             }
463         } catch (XmlPullParserException e) {
464             e.printStackTrace();
465         }
466         return features;
467     }
468 
generateFeatureList(XmlResourceParser parser)469     private SsFeature generateFeatureList(XmlResourceParser parser)
470             throws XmlPullParserException, IOException {
471         SsFeature ssfeature = new SsFeature();
472         int outerDepth = parser.getDepth();
473 
474         Log.d(LOG_TAG, "generateFeatureList outerDepth" + outerDepth);
475 
476         while (parser.next() != XmlPullParser.END_DOCUMENT) {
477             Log.d(LOG_TAG, "generateFeatureList parser.getDepth()" + parser.getDepth());
478 
479             int eventType = parser.getEventType();
480             if (eventType == XmlPullParser.END_TAG
481                     && outerDepth == parser.getDepth()) {
482                 break;
483             }
484 
485             if (eventType != XmlPullParser.START_TAG) {
486                 continue;
487             }
488             String name = parser.getName();
489             // Starts by looking for the command tag.
490             if (TAG_COMMAND.equals(name)) {
491                 SsEntry entry = readCommandEntry(parser);
492                 ssfeature.ssEntryHashMap.put(entry.ssAction, entry);
493             } else if (TAG_COMMAND_RESULT.equals(name)) {
494                 readCommandResultEntry(parser, ssfeature);
495             }
496         }
497         return ssfeature;
498     }
499 
readCommandResultEntry(XmlResourceParser parser, SsFeature ssFeature)500     private void readCommandResultEntry(XmlResourceParser parser, SsFeature ssFeature)
501             throws XmlPullParserException, IOException {
502         while (parser.next() != XmlPullParser.END_DOCUMENT) {
503             int eventType = parser.getEventType();
504             if (eventType == XmlPullParser.END_TAG
505                     && TAG_COMMAND_RESULT.equals(parser.getName())) {
506                 break;
507             }
508             if (eventType == XmlPullParser.START_TAG
509                     && TAG_ENTRY.equals(parser.getName())) {
510                 String key = getSpecificAttributeValue(parser, ATTR_RESULT_KEY);
511                 if (!TextUtils.isEmpty(key)) {
512                     SsResultEntry entry = new SsResultEntry();
513                     entry.mDefinition = getSpecificAttributeValue(parser, ATTR_DEFINITION_KEY);
514                     entry.mCompareValue = readText(parser);
515                     if (ssFeature.responseCode.containsKey(key)) {
516                         ssFeature.responseCode.get(key).add(entry);
517                     } else {
518                         ArrayList<SsResultEntry> arrayList = new ArrayList<>();
519                         arrayList.add(entry);
520                         ssFeature.responseCode.put(key, arrayList);
521                     }
522                 }
523             }
524         }
525     }
526 
readCommandEntry(XmlResourceParser parser)527     private SsEntry readCommandEntry(XmlResourceParser parser)
528             throws XmlPullParserException, IOException {
529         int outerDepth = parser.getDepth();
530         String command_action = getSpecificAttributeValue(parser, ATTR_NAME);
531         SsEntry entry = new SsEntry(command_action);
532 
533         while (parser.next() != XmlPullParser.END_DOCUMENT) {
534             int eventType = parser.getEventType();
535             if (eventType == XmlPullParser.END_TAG
536                     && outerDepth == parser.getDepth()) {
537                 break;
538             }
539 
540             if (eventType != XmlPullParser.START_TAG) {
541                 continue;
542             }
543 
544             String name = parser.getName();
545             if (TAG_SERVICE_CODE.equals(name)) {
546                 entry.serviceCode = readText(parser);
547             } else if (TAG_ACTION_CODE.equals(name)) {
548                 entry.actionCode = readText(parser);
549             } else if (TAG_PARAMETER.equals(name)) {
550                 String number = getSpecificAttributeValue(parser, ATTR_PARAMETER_NUM);
551                 if (!TextUtils.isEmpty(number)) {
552                     readParameters(parser, entry, Integer.valueOf(number), TAG_PARAMETER);
553                 }
554             } else if (TAG_RESPONSE_FORMAT.equals(name)) {
555                 String number = getSpecificAttributeValue(parser, ATTR_PARAMETER_NUM);
556                 if (!TextUtils.isEmpty(number)) {
557                     readParameters(parser, entry, Integer.valueOf(number), TAG_RESPONSE_FORMAT);
558                 }
559             }
560         }
561         Log.d(LOG_TAG, "ssEntry:" + entry.toString());
562         return entry;
563     }
564 
readParameters(XmlResourceParser parser, SsEntry entry, int num, String parentTag)565     private void readParameters(XmlResourceParser parser, SsEntry entry, int num, String parentTag)
566             throws IOException, XmlPullParserException {
567         Log.d(LOG_TAG, "readParameters() nume:" + num);
568         int i = 0;
569         while (i < num) {
570             if (parser.next() == XmlPullParser.START_TAG) {
571                 String name = parser.getName();
572                 if (TAG_ENTRY.equals(name)) {
573                     String position = getSpecificAttributeValue(parser, ATTR_POSITION);
574                     if (!TextUtils.isEmpty(position)) {
575                         if (TAG_PARAMETER.equals(parentTag)) {
576                             String value = readText(parser);
577                             if (!TextUtils.isEmpty(value)) {
578                                 entry.commandParameter.put(Integer.valueOf(position), value);
579                             }
580                         } else if (TAG_RESPONSE_FORMAT.equals(parentTag)) {
581                             String key = getSpecificAttributeValue(parser, ATTR_RESULT_KEY);
582                             if (!TextUtils.isEmpty(key)) {
583                                 entry.responseFormat.put(Integer.valueOf(position), key);
584                             }
585                         }
586                         i++;
587                     }
588                 }
589             }
590         }
591     }
592 
getSpecificAttributeValue(XmlResourceParser parser, String attrTag)593     private String getSpecificAttributeValue(XmlResourceParser parser, String attrTag) {
594         String value = "";
595         for (int i = 0; i < parser.getAttributeCount(); i++) {
596             if (attrTag.equals(parser.getAttributeName(i))) {
597                 value = parser.getAttributeValue(i);
598             }
599         }
600         return value;
601     }
602 
readText(XmlResourceParser parser)603     private String readText(XmlResourceParser parser) throws IOException, XmlPullParserException {
604         String result = "";
605         if (parser.next() == XmlPullParser.TEXT) {
606             result = parser.getText();
607             parser.nextTag();
608         }
609         return result;
610     }
611 
612     /**
613      * CarrierXmlParser parses the xml and saves in mFeatureMap.
614      * To use this function get feature from the mFeatureMaps.
615      *
616      * @param inputFeatureName This is feature's name from xml.
617      */
getFeature(String inputFeatureName)618     public SsFeature getFeature(String inputFeatureName) {
619         return mFeatureMaps.get(inputFeatureName);
620     }
621 
622     /**
623      * To check the command which is dialed by user is caller id command.
624      * <p>
625      * If it is a caller id command which sets to activate, return the {@code
626      * SsEntry.SSAction.UPDATE_ACTIVATE}.
627      * If it is a caller id command which sets to deactivate, return the {@code
628      * SsEntry.SSAction.UPDATE_DEACTIVATE}.
629      * If it is not a caller id command, return the {@code SsEntry.SSAction.UNKNOWN}.
630      *
631      * @param inputCommand This is caller id's ussd command which is dialed by user.
632      * @return {@link SsEntry.SSAction}
633      */
getCallerIdUssdCommandAction(String inputCommand)634     public SsEntry.SSAction getCallerIdUssdCommandAction(String inputCommand) {
635         if (isCallerIdActivate(inputCommand)) {
636             return SsEntry.SSAction.UPDATE_ACTIVATE;
637         }
638         if (isCallerIdDeactivate(inputCommand)) {
639             return SsEntry.SSAction.UPDATE_DEACTIVATE;
640         }
641         return SsEntry.SSAction.UNKNOWN;
642     }
643 
getCallerIdActivateCommandFromXml()644     private String getCallerIdActivateCommandFromXml() {
645         return getFeature(FEATURE_CALLER_ID).getCommandStructure(SsEntry.SSAction.UPDATE_ACTIVATE);
646     }
647 
getCallerIdDeactivateCommandFromXml()648     private String getCallerIdDeactivateCommandFromXml() {
649         return getFeature(FEATURE_CALLER_ID).getCommandStructure(
650                 SsEntry.SSAction.UPDATE_DEACTIVATE);
651     }
652 
isCallerIdActivate(String inputStr)653     private boolean isCallerIdActivate(String inputStr) {
654         String activateStr = getCallerIdActivateCommandFromXml();
655         return compareCommand(activateStr, inputStr);
656     }
657 
isCallerIdDeactivate(String inputStr)658     private boolean isCallerIdDeactivate(String inputStr) {
659         String activateStr = getCallerIdDeactivateCommandFromXml();
660         return compareCommand(activateStr, inputStr);
661     }
662 
compareCommand(String activateStr, String inputStr)663     private boolean compareCommand(String activateStr, String inputStr) {
664         String[] activateArray = activateStr.split("\\" + STAR_SIGN);
665         String[] inputArray = inputStr.split("\\" + STAR_SIGN);
666 
667         if (activateArray.length == 0 || inputArray.length == 0) {
668             return false;
669         }
670         for (int i = 0; i < activateArray.length; i++) {
671             if (activateArray[i].startsWith(TAG_SIGN)) {
672                 continue;
673             }
674             if (!activateArray[i].equals(inputArray[i])) {
675                 Log.d(LOG_TAG, "compare fails:" + activateStr + "," + inputStr);
676                 return false;
677             }
678         }
679         Log.d(LOG_TAG, "compare success");
680         return true;
681     }
682 }
683