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