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