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