1 /*
2  * Copyright (C) 2016 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.stk;
18 
19 import android.content.Context;
20 import android.content.res.XmlResourceParser;
21 import android.graphics.Bitmap;
22 import android.graphics.BitmapFactory;
23 import android.telephony.SubscriptionInfo;
24 import android.telephony.SubscriptionManager;
25 import android.telephony.TelephonyManager;
26 import android.text.TextUtils;
27 
28 import com.android.internal.telephony.PhoneConstants;
29 import com.android.internal.telephony.cat.CatLog;
30 import com.android.internal.telephony.util.TelephonyUtils;
31 import com.android.internal.telephony.util.XmlUtils;
32 
33 import java.util.ArrayList;
34 
35 /**
36  * Provides preset label and/or icon in accordance with mcc/mnc
37  * conbination of the inserted SIM card for Multi-SIM model.
38  */
39 public class StkMenuConfig {
40     private static final String LOG_TAG =
41             new Object(){}.getClass().getEnclosingClass().getSimpleName();
42     private static final boolean DBG = TelephonyUtils.IS_DEBUGGABLE;
43 
44     private static final String XML_OPERATORS_TAG = "operators";
45     private static final String XML_OPERATOR_TAG = "operator";
46 
47     private static final String XML_MCC_ATTR = "mcc";
48     private static final String XML_MNC_ATTR = "mnc";
49     private static final String XML_LABEL_ATTR = "label";
50     private static final String XML_ICON_ATTR = "icon";
51     private static final String RESOURCE_TYPE = "drawable";
52 
53     private static final int UNSPECIFIED = -1;
54 
55     private static final Config NO_CONFIG = new Config(0, 0, null, null);
56 
57     private static final Object sLock = new Object();
58     private static StkMenuConfig sInstance;
59 
60     private Context mContext;
61     private ArrayList<Config> mArray;
62     private Config mConfigs[] = null;
63 
64     private static class Config {
65         public int mcc;
66         public int mnc;
67         public String label;
68         public String icon;
69 
Config(int mcc, int mnc, String label, String icon)70         public Config(int mcc, int mnc, String label, String icon) {
71             this.mcc = mcc;
72             this.mnc = mnc;
73             this.label = label;
74             this.icon = icon;
75         }
76     }
77 
getInstance(Context applicationContext)78     public static StkMenuConfig getInstance(Context applicationContext) {
79         synchronized (sLock) {
80             if (sInstance == null) {
81                 sInstance = new StkMenuConfig();
82                 sInstance.initialize(applicationContext);
83             }
84             return sInstance;
85         }
86     }
87 
88     /**
89      * Returns a preset label, if exists.
90      */
getLabel(int slotId)91     public String getLabel(int slotId) {
92         findConfig(slotId);
93 
94         if (DBG) CatLog.d(LOG_TAG, "getLabel: " + mConfigs[slotId].label + ", slot id: " + slotId);
95         return mConfigs[slotId].label;
96     }
97 
98     /**
99      * Returns a preset icon, if exists.
100      */
getIcon(int slotId)101     public Bitmap getIcon(int slotId) {
102         findConfig(slotId);
103 
104         Bitmap bitmap = null;
105         if (mConfigs[slotId].icon != null) {
106             int resId = mContext.getResources().getIdentifier(mConfigs[slotId].icon,
107                     RESOURCE_TYPE, mContext.getPackageName());
108             bitmap = resId == UNSPECIFIED ? null :
109                     BitmapFactory.decodeResource(mContext.getResources(), resId);
110         }
111         if (DBG) CatLog.d(LOG_TAG, "getIcon: " + mConfigs[slotId].icon + ", slot id: " + slotId);
112         return bitmap;
113     }
114 
findConfig(int slotId)115     private void findConfig(int slotId) {
116         SubscriptionManager sm = (SubscriptionManager) mContext.getSystemService(
117                 Context.TELEPHONY_SUBSCRIPTION_SERVICE);
118         SubscriptionInfo info = (sm != null) ? sm.getActiveSubscriptionInfoForSimSlotIndex(slotId)
119                 : null;
120         if (info == null) {
121             mConfigs[slotId] = NO_CONFIG;
122             return;
123         }
124 
125         TelephonyManager telephony =
126                 (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
127         String operator = telephony.getSimOperator(info.getSubscriptionId());
128         if (TextUtils.isEmpty(operator) || (operator.length() < 5)) {
129             mConfigs[slotId] = NO_CONFIG;
130             return;
131         }
132 
133         int mcc = Integer.parseInt(operator.substring(0, 3));
134         int mnc = Integer.parseInt(operator.substring(3));
135 
136         if (mConfigs[slotId] != null && mConfigs[slotId].mcc == mcc
137                 && mConfigs[slotId].mnc == mnc) {
138             if (DBG) CatLog.d(LOG_TAG, "Return the cached config, slot id: " + slotId);
139             return;
140         }
141 
142         if (DBG) CatLog.d(LOG_TAG, "Find config and create the cached config, slot id: " + slotId);
143         for (Config config : mArray) {
144             if ((config.mcc == mcc) && (config.mnc == mnc)) {
145                 mConfigs[slotId] = config;
146                 return;
147             }
148         }
149 
150         mConfigs[slotId] = new Config(mcc, mnc, null, null);
151     }
152 
initialize(Context context)153     private void initialize(Context context) {
154         mContext = context;
155         mArray = new ArrayList<Config>();
156         mConfigs = new Config[TelephonyManager.from(mContext).getSupportedModemCount()];
157 
158         XmlResourceParser parser = mContext.getResources().getXml(R.xml.menu_conf);
159 
160         try {
161             XmlUtils.beginDocument(parser, XML_OPERATORS_TAG);
162 
163             do {
164                 XmlUtils.nextElement(parser);
165 
166                 if (!XML_OPERATOR_TAG.equals(parser.getName())) {
167                     break;
168                 }
169 
170                 int mcc = parser.getAttributeIntValue(null, XML_MCC_ATTR, UNSPECIFIED);
171                 int mnc = parser.getAttributeIntValue(null, XML_MNC_ATTR, UNSPECIFIED);
172 
173                 if ((mcc == UNSPECIFIED) || (mnc == UNSPECIFIED)) {
174                     continue;
175                 }
176 
177                 String label = parser.getAttributeValue(null, XML_LABEL_ATTR);
178                 String icon = parser.getAttributeValue(null, XML_ICON_ATTR);
179 
180                 Config config = new Config(mcc, mnc, label, icon);
181                 mArray.add(config);
182             } while (true);
183         } catch (Exception e) {
184             CatLog.e(LOG_TAG, "Something wrong happened while interpreting the xml file" + e);
185         } finally {
186             parser.close();
187         }
188     }
189 }
190