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
17package com.android.internal.telephony.cdma;
18
19import android.content.Context;
20import android.content.res.Resources;
21import android.content.res.XmlResourceParser;
22import android.os.PersistableBundle;
23import android.telephony.CarrierConfigManager;
24import android.telephony.Rlog;
25import android.util.Xml;
26
27import com.android.internal.telephony.Phone;
28import com.android.internal.util.XmlUtils;
29
30
31import org.xmlpull.v1.XmlPullParser;
32import org.xmlpull.v1.XmlPullParserException;
33
34import java.io.FileInputStream;
35import java.io.FileNotFoundException;
36import java.io.IOException;
37import java.util.HashMap;
38
39/**
40 * EriManager loads the ERI file definitions and manages the CDMA roaming information.
41 *
42 */
43public 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
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
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
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
102    public EriManager(Phone phone, Context context, int eriFileSource) {
103        mPhone = phone;
104        mContext = context;
105        mEriFileSource = eriFileSource;
106        mEriFile = new EriFile();
107    }
108
109    public void dispose() {
110        mEriFile = new EriFile();
111        mIsEriFileLoaded = false;
112    }
113
114
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     */
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     */
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     */
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     */
271    public int getEriFileVersion() {
272        return mEriFile.mVersionNumber;
273    }
274
275    /**
276     * Returns the number of ERI entries parsed
277     *
278     */
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     */
287    public int getEriFileType() {
288        return mEriFile.mEriFileType;
289    }
290
291    /**
292     * Returns if the ERI file has been loaded
293     *
294     */
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     */
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
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
506    public int getCdmaEriIconIndex(int roamInd, int defRoamInd){
507        return getEriDisplayInformation(roamInd, defRoamInd).mEriIconIndex;
508    }
509
510    public int getCdmaEriIconMode(int roamInd, int defRoamInd){
511        return getEriDisplayInformation(roamInd, defRoamInd).mEriIconMode;
512    }
513
514    public String getCdmaEriText(int roamInd, int defRoamInd){
515        return getEriDisplayInformation(roamInd, defRoamInd).mEriIconText;
516    }
517}
518