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