1 /*
2  * Copyright (C) 2009 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.internal.telephony.cdma;
18 
19 import android.annotation.UnsupportedAppUsage;
20 import android.content.Context;
21 import android.content.res.Resources;
22 import android.content.res.XmlResourceParser;
23 import android.os.PersistableBundle;
24 import android.telephony.CarrierConfigManager;
25 import android.telephony.Rlog;
26 import android.util.Xml;
27 
28 import com.android.internal.telephony.Phone;
29 import com.android.internal.util.XmlUtils;
30 
31 
32 import org.xmlpull.v1.XmlPullParser;
33 import org.xmlpull.v1.XmlPullParserException;
34 
35 import java.io.FileInputStream;
36 import java.io.FileNotFoundException;
37 import java.io.IOException;
38 import java.util.HashMap;
39 
40 /**
41  * EriManager loads the ERI file definitions and manages the CDMA roaming information.
42  *
43  */
44 public class EriManager {
45 
46     class EriFile {
47 
48         int mVersionNumber;                      // File version number
49         int mNumberOfEriEntries;                 // Number of entries
50         int mEriFileType;                        // Eri Phase 0/1
51         //int mNumberOfIconImages;               // reserved for future use
52         //int mIconImageType;                    // reserved for future use
53         String[] mCallPromptId;                  // reserved for future use
54         HashMap<Integer, EriInfo> mRoamIndTable; // Roaming Indicator Table
55 
EriFile()56         EriFile() {
57             mVersionNumber = -1;
58             mNumberOfEriEntries = 0;
59             mEriFileType = -1;
60             mCallPromptId = new String[] { "", "", "" };
61             mRoamIndTable = new HashMap<Integer, EriInfo>();
62         }
63     }
64 
65     class EriDisplayInformation {
66         int mEriIconIndex;
67         int mEriIconMode;
68         @UnsupportedAppUsage
69         String mEriIconText;
70 
EriDisplayInformation(int eriIconIndex, int eriIconMode, String eriIconText)71         EriDisplayInformation(int eriIconIndex, int eriIconMode, String eriIconText) {
72             mEriIconIndex = eriIconIndex;
73             mEriIconMode = eriIconMode;
74             mEriIconText = eriIconText;
75         }
76 
77 //        public void setParameters(int eriIconIndex, int eriIconMode, String eriIconText){
78 //            mEriIconIndex = eriIconIndex;
79 //            mEriIconMode = eriIconMode;
80 //            mEriIconText = eriIconText;
81 //        }
82 
83         @Override
toString()84         public String toString() {
85             return "EriDisplayInformation: {" + " IconIndex: " + mEriIconIndex + " EriIconMode: "
86                     + mEriIconMode + " EriIconText: " + mEriIconText + " }";
87         }
88     }
89 
90     private static final String LOG_TAG = "EriManager";
91     private static final boolean DBG = true;
92     private static final boolean VDBG = false;
93 
94     public static final int ERI_FROM_XML   = 0;
95     static final int ERI_FROM_FILE_SYSTEM  = 1;
96     static final int ERI_FROM_MODEM        = 2;
97 
98     private Context mContext;
99     private int mEriFileSource = ERI_FROM_XML;
100     private boolean mIsEriFileLoaded;
101     private EriFile mEriFile;
102     private final Phone mPhone;
103 
EriManager(Phone phone, int eriFileSource)104     public EriManager(Phone phone, int eriFileSource) {
105         mPhone = phone;
106         mContext = mPhone.getContext();
107         mEriFileSource = eriFileSource;
108         mEriFile = new EriFile();
109     }
110 
dispose()111     public void dispose() {
112         mEriFile = new EriFile();
113         mIsEriFileLoaded = false;
114     }
115 
116 
loadEriFile()117     public void loadEriFile() {
118         switch (mEriFileSource) {
119         case ERI_FROM_MODEM:
120             loadEriFileFromModem();
121             break;
122 
123         case ERI_FROM_FILE_SYSTEM:
124             loadEriFileFromFileSystem();
125             break;
126 
127         case ERI_FROM_XML:
128         default:
129             loadEriFileFromXml();
130             break;
131         }
132     }
133 
134     /**
135      * Load the ERI file from the MODEM through chipset specific RIL_REQUEST_OEM_HOOK
136      *
137      * In this case the ERI file can be updated from the Phone Support Tool available
138      * from the Chipset vendor
139      */
loadEriFileFromModem()140     private void loadEriFileFromModem() {
141         // NOT IMPLEMENTED, Chipset vendor/Operator specific
142     }
143 
144     /**
145      * Load the ERI file from a File System file
146      *
147      * In this case the a Phone Support Tool to update the ERI file must be provided
148      * to the Operator
149      */
loadEriFileFromFileSystem()150     private void loadEriFileFromFileSystem() {
151         // NOT IMPLEMENTED, Chipset vendor/Operator specific
152     }
153 
154     /**
155      * Load the ERI file from the application framework resources encoded in XML
156      *
157      */
loadEriFileFromXml()158     private void loadEriFileFromXml() {
159         XmlPullParser parser = null;
160         FileInputStream stream = null;
161         Resources r = mContext.getResources();
162 
163         try {
164             if (DBG) Rlog.d(LOG_TAG, "loadEriFileFromXml: check for alternate file");
165             stream = new FileInputStream(
166                             r.getString(com.android.internal.R.string.alternate_eri_file));
167             parser = Xml.newPullParser();
168             parser.setInput(stream, null);
169             if (DBG) Rlog.d(LOG_TAG, "loadEriFileFromXml: opened alternate file");
170         } catch (FileNotFoundException e) {
171             if (DBG) Rlog.d(LOG_TAG, "loadEriFileFromXml: no alternate file");
172             parser = null;
173         } catch (XmlPullParserException e) {
174             if (DBG) Rlog.d(LOG_TAG, "loadEriFileFromXml: no parser for alternate file");
175             parser = null;
176         }
177 
178         if (parser == null) {
179             String eriFile = null;
180 
181             CarrierConfigManager configManager = (CarrierConfigManager)
182                     mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
183             if (configManager != null) {
184                 PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId());
185                 if (b != null) {
186                     eriFile = b.getString(CarrierConfigManager.KEY_CARRIER_ERI_FILE_NAME_STRING);
187                 }
188             }
189 
190             Rlog.d(LOG_TAG, "eriFile = " + eriFile);
191 
192             if (eriFile == null) {
193                 if (DBG) Rlog.e(LOG_TAG, "loadEriFileFromXml: Can't find ERI file to load");
194                 return;
195             }
196 
197             try {
198                 parser = Xml.newPullParser();
199                 parser.setInput(mContext.getAssets().open(eriFile), null);
200             } catch (IOException | XmlPullParserException e) {
201                 if (DBG) Rlog.e(LOG_TAG, "loadEriFileFromXml: no parser for " + eriFile +
202                         ". Exception = " + e.toString());
203             }
204         }
205 
206         try {
207             XmlUtils.beginDocument(parser, "EriFile");
208             mEriFile.mVersionNumber = Integer.parseInt(
209                     parser.getAttributeValue(null, "VersionNumber"));
210             mEriFile.mNumberOfEriEntries = Integer.parseInt(
211                     parser.getAttributeValue(null, "NumberOfEriEntries"));
212             mEriFile.mEriFileType = Integer.parseInt(
213                     parser.getAttributeValue(null, "EriFileType"));
214 
215             int parsedEriEntries = 0;
216             while(true) {
217                 XmlUtils.nextElement(parser);
218                 String name = parser.getName();
219                 if (name == null) {
220                     if (parsedEriEntries != mEriFile.mNumberOfEriEntries)
221                         Rlog.e(LOG_TAG, "Error Parsing ERI file: " +  mEriFile.mNumberOfEriEntries
222                                 + " defined, " + parsedEriEntries + " parsed!");
223                     break;
224                 } else if (name.equals("CallPromptId")) {
225                     int id = Integer.parseInt(parser.getAttributeValue(null, "Id"));
226                     String text = parser.getAttributeValue(null, "CallPromptText");
227                     if (id >= 0 && id <= 2) {
228                         mEriFile.mCallPromptId[id] = text;
229                     } else {
230                         Rlog.e(LOG_TAG, "Error Parsing ERI file: found" + id + " CallPromptId");
231                     }
232 
233                 } else if (name.equals("EriInfo")) {
234                     int roamingIndicator = Integer.parseInt(
235                             parser.getAttributeValue(null, "RoamingIndicator"));
236                     int iconIndex = Integer.parseInt(parser.getAttributeValue(null, "IconIndex"));
237                     int iconMode = Integer.parseInt(parser.getAttributeValue(null, "IconMode"));
238                     String eriText = parser.getAttributeValue(null, "EriText");
239                     int callPromptId = Integer.parseInt(
240                             parser.getAttributeValue(null, "CallPromptId"));
241                     int alertId = Integer.parseInt(parser.getAttributeValue(null, "AlertId"));
242                     parsedEriEntries++;
243                     mEriFile.mRoamIndTable.put(roamingIndicator, new EriInfo (roamingIndicator,
244                             iconIndex, iconMode, eriText, callPromptId, alertId));
245                 }
246             }
247 
248             Rlog.d(LOG_TAG, "loadEriFileFromXml: eri parsing successful, file loaded. ver = " +
249                     mEriFile.mVersionNumber + ", # of entries = " + mEriFile.mNumberOfEriEntries);
250 
251             mIsEriFileLoaded = true;
252 
253         } catch (Exception e) {
254             Rlog.e(LOG_TAG, "Got exception while loading ERI file.", e);
255         } finally {
256             if (parser instanceof XmlResourceParser) {
257                 ((XmlResourceParser)parser).close();
258             }
259             try {
260                 if (stream != null) {
261                     stream.close();
262                 }
263             } catch (IOException e) {
264                 // Ignore
265             }
266         }
267     }
268 
269     /**
270      * Returns the version of the ERI file
271      *
272      */
getEriFileVersion()273     public int getEriFileVersion() {
274         return mEriFile.mVersionNumber;
275     }
276 
277     /**
278      * Returns the number of ERI entries parsed
279      *
280      */
getEriNumberOfEntries()281     public int getEriNumberOfEntries() {
282         return mEriFile.mNumberOfEriEntries;
283     }
284 
285     /**
286      * Returns the ERI file type value ( 0 for Phase 0, 1 for Phase 1)
287      *
288      */
getEriFileType()289     public int getEriFileType() {
290         return mEriFile.mEriFileType;
291     }
292 
293     /**
294      * Returns if the ERI file has been loaded
295      *
296      */
isEriFileLoaded()297     public boolean isEriFileLoaded() {
298         return mIsEriFileLoaded;
299     }
300 
301     /**
302      * Returns the EriInfo record associated with roamingIndicator
303      * or null if the entry is not found
304      */
getEriInfo(int roamingIndicator)305     private EriInfo getEriInfo(int roamingIndicator) {
306         if (mEriFile.mRoamIndTable.containsKey(roamingIndicator)) {
307             return mEriFile.mRoamIndTable.get(roamingIndicator);
308         } else {
309             return null;
310         }
311     }
312 
313     @UnsupportedAppUsage
getEriDisplayInformation(int roamInd, int defRoamInd)314     private EriDisplayInformation getEriDisplayInformation(int roamInd, int defRoamInd){
315         EriDisplayInformation ret;
316 
317         // Carrier can use carrier config to customize any built-in roaming display indications
318         if (mIsEriFileLoaded) {
319             EriInfo eriInfo = getEriInfo(roamInd);
320             if (eriInfo != null) {
321                 if (VDBG) Rlog.v(LOG_TAG, "ERI roamInd " + roamInd + " found in ERI file");
322                 ret = new EriDisplayInformation(
323                         eriInfo.iconIndex,
324                         eriInfo.iconMode,
325                         eriInfo.eriText);
326                 return ret;
327             }
328         }
329 
330         switch (roamInd) {
331         // Handling the standard roaming indicator (non-ERI)
332         case EriInfo.ROAMING_INDICATOR_ON:
333             ret = new EriDisplayInformation(
334                     EriInfo.ROAMING_INDICATOR_ON,
335                     EriInfo.ROAMING_ICON_MODE_NORMAL,
336                     mContext.getText(com.android.internal.R.string.roamingText0).toString());
337             break;
338 
339         case EriInfo.ROAMING_INDICATOR_OFF:
340             ret = new EriDisplayInformation(
341                     EriInfo.ROAMING_INDICATOR_OFF,
342                     EriInfo.ROAMING_ICON_MODE_NORMAL,
343                     mContext.getText(com.android.internal.R.string.roamingText1).toString());
344             break;
345 
346         case EriInfo.ROAMING_INDICATOR_FLASH:
347             ret = new EriDisplayInformation(
348                     EriInfo.ROAMING_INDICATOR_FLASH,
349                     EriInfo.ROAMING_ICON_MODE_FLASH,
350                     mContext.getText(com.android.internal.R.string.roamingText2).toString());
351             break;
352 
353 
354         // Handling the standard ERI
355         case 3:
356             ret = new EriDisplayInformation(
357                     roamInd,
358                     EriInfo.ROAMING_ICON_MODE_NORMAL,
359                     mContext.getText(com.android.internal.R.string.roamingText3).toString());
360             break;
361 
362         case 4:
363             ret = new EriDisplayInformation(
364                     roamInd,
365                     EriInfo.ROAMING_ICON_MODE_NORMAL,
366                     mContext.getText(com.android.internal.R.string.roamingText4).toString());
367             break;
368 
369         case 5:
370             ret = new EriDisplayInformation(
371                     roamInd,
372                     EriInfo.ROAMING_ICON_MODE_NORMAL,
373                     mContext.getText(com.android.internal.R.string.roamingText5).toString());
374             break;
375 
376         case 6:
377             ret = new EriDisplayInformation(
378                     roamInd,
379                     EriInfo.ROAMING_ICON_MODE_NORMAL,
380                     mContext.getText(com.android.internal.R.string.roamingText6).toString());
381             break;
382 
383         case 7:
384             ret = new EriDisplayInformation(
385                     roamInd,
386                     EriInfo.ROAMING_ICON_MODE_NORMAL,
387                     mContext.getText(com.android.internal.R.string.roamingText7).toString());
388             break;
389 
390         case 8:
391             ret = new EriDisplayInformation(
392                     roamInd,
393                     EriInfo.ROAMING_ICON_MODE_NORMAL,
394                     mContext.getText(com.android.internal.R.string.roamingText8).toString());
395             break;
396 
397         case 9:
398             ret = new EriDisplayInformation(
399                     roamInd,
400                     EriInfo.ROAMING_ICON_MODE_NORMAL,
401                     mContext.getText(com.android.internal.R.string.roamingText9).toString());
402             break;
403 
404         case 10:
405             ret = new EriDisplayInformation(
406                     roamInd,
407                     EriInfo.ROAMING_ICON_MODE_NORMAL,
408                     mContext.getText(com.android.internal.R.string.roamingText10).toString());
409             break;
410 
411         case 11:
412             ret = new EriDisplayInformation(
413                     roamInd,
414                     EriInfo.ROAMING_ICON_MODE_NORMAL,
415                     mContext.getText(com.android.internal.R.string.roamingText11).toString());
416             break;
417 
418         case 12:
419             ret = new EriDisplayInformation(
420                     roamInd,
421                     EriInfo.ROAMING_ICON_MODE_NORMAL,
422                     mContext.getText(com.android.internal.R.string.roamingText12).toString());
423             break;
424 
425         // Handling the non standard Enhanced Roaming Indicator (roamInd > 63)
426         default:
427             if (!mIsEriFileLoaded) {
428                 // ERI file NOT loaded
429                 if (DBG) Rlog.d(LOG_TAG, "ERI File not loaded");
430                 if(defRoamInd > 2) {
431                     if (VDBG) Rlog.v(LOG_TAG, "ERI defRoamInd > 2 ...flashing");
432                     ret = new EriDisplayInformation(
433                             EriInfo.ROAMING_INDICATOR_FLASH,
434                             EriInfo.ROAMING_ICON_MODE_FLASH,
435                             mContext.getText(com.android.internal
436                                                             .R.string.roamingText2).toString());
437                 } else {
438                     if (VDBG) Rlog.v(LOG_TAG, "ERI defRoamInd <= 2");
439                     switch (defRoamInd) {
440                     case EriInfo.ROAMING_INDICATOR_ON:
441                         ret = new EriDisplayInformation(
442                                 EriInfo.ROAMING_INDICATOR_ON,
443                                 EriInfo.ROAMING_ICON_MODE_NORMAL,
444                                 mContext.getText(com.android.internal
445                                                             .R.string.roamingText0).toString());
446                         break;
447 
448                     case EriInfo.ROAMING_INDICATOR_OFF:
449                         ret = new EriDisplayInformation(
450                                 EriInfo.ROAMING_INDICATOR_OFF,
451                                 EriInfo.ROAMING_ICON_MODE_NORMAL,
452                                 mContext.getText(com.android.internal
453                                                             .R.string.roamingText1).toString());
454                         break;
455 
456                     case EriInfo.ROAMING_INDICATOR_FLASH:
457                         ret = new EriDisplayInformation(
458                                 EriInfo.ROAMING_INDICATOR_FLASH,
459                                 EriInfo.ROAMING_ICON_MODE_FLASH,
460                                 mContext.getText(com.android.internal
461                                                             .R.string.roamingText2).toString());
462                         break;
463 
464                     default:
465                         ret = new EriDisplayInformation(-1, -1, "ERI text");
466                     }
467                 }
468             } else {
469                 // ERI file loaded
470                 EriInfo eriInfo = getEriInfo(roamInd);
471                 EriInfo defEriInfo = getEriInfo(defRoamInd);
472                 if (eriInfo == null) {
473                     if (VDBG) {
474                         Rlog.v(LOG_TAG, "ERI roamInd " + roamInd
475                             + " not found in ERI file ...using defRoamInd " + defRoamInd);
476                     }
477                     if(defEriInfo == null) {
478                         Rlog.e(LOG_TAG, "ERI defRoamInd " + defRoamInd
479                                 + " not found in ERI file ...on");
480                         ret = new EriDisplayInformation(
481                                 EriInfo.ROAMING_INDICATOR_ON,
482                                 EriInfo.ROAMING_ICON_MODE_NORMAL,
483                                 mContext.getText(com.android.internal
484                                                              .R.string.roamingText0).toString());
485 
486                     } else {
487                         if (VDBG) {
488                             Rlog.v(LOG_TAG, "ERI defRoamInd " + defRoamInd + " found in ERI file");
489                         }
490                         ret = new EriDisplayInformation(
491                                 defEriInfo.iconIndex,
492                                 defEriInfo.iconMode,
493                                 defEriInfo.eriText);
494                     }
495                 } else {
496                     if (VDBG) Rlog.v(LOG_TAG, "ERI roamInd " + roamInd + " found in ERI file");
497                     ret = new EriDisplayInformation(
498                             eriInfo.iconIndex,
499                             eriInfo.iconMode,
500                             eriInfo.eriText);
501                 }
502             }
503             break;
504         }
505         if (VDBG) Rlog.v(LOG_TAG, "Displaying ERI " + ret.toString());
506         return ret;
507     }
508 
getCdmaEriIconIndex(int roamInd, int defRoamInd)509     public int getCdmaEriIconIndex(int roamInd, int defRoamInd){
510         return getEriDisplayInformation(roamInd, defRoamInd).mEriIconIndex;
511     }
512 
getCdmaEriIconMode(int roamInd, int defRoamInd)513     public int getCdmaEriIconMode(int roamInd, int defRoamInd){
514         return getEriDisplayInformation(roamInd, defRoamInd).mEriIconMode;
515     }
516 
getCdmaEriText(int roamInd, int defRoamInd)517     public String getCdmaEriText(int roamInd, int defRoamInd){
518         return getEriDisplayInformation(roamInd, defRoamInd).mEriIconText;
519     }
520 }
521