1/*
2 * Copyright (C) 2014 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.mms.service;
18
19import android.content.Context;
20import android.content.res.XmlResourceParser;
21import android.os.Bundle;
22import android.telephony.SubscriptionManager;
23import android.telephony.TelephonyManager;
24import android.text.TextUtils;
25import android.util.Base64;
26import android.util.Log;
27
28import java.io.UnsupportedEncodingException;
29import java.util.Iterator;
30import java.util.Map;
31import java.util.concurrent.ConcurrentHashMap;
32
33/**
34 * This class manages a cached copy of current MMS configuration key values
35 *
36 * The steps to add a key
37 * 1. Add a String constant for the key
38 * 2. Add a default value for the key by putting a typed value to DEFAULTS
39 *    (null means String type only)
40 * 3. Add a getter for the key
41 * 4. Add key/value for relevant mms_config.xml of a specific carrier (mcc/mnc)
42 */
43public class MmsConfig {
44    private static final String TAG = MmsService.TAG;
45
46    private static final String DEFAULT_HTTP_KEY_X_WAP_PROFILE = "x-wap-profile";
47
48    private static final int MAX_IMAGE_HEIGHT = 480;
49    private static final int MAX_IMAGE_WIDTH = 640;
50    private static final int MAX_TEXT_LENGTH = 2000;
51
52    /*
53     * MmsConfig keys. These have to stay in sync with the MMS_CONFIG_* values defined in
54     * SmsManager.
55     */
56    public static final String CONFIG_ENABLED_MMS = "enabledMMS";
57    // In case of single segment wap push message, this CONFIG_ENABLED_TRANS_ID indicates whether
58    // TransactionID should be appended to URI or not.
59    public static final String CONFIG_ENABLED_TRANS_ID = "enabledTransID";
60    public static final String CONFIG_ENABLED_NOTIFY_WAP_MMSC = "enabledNotifyWapMMSC";
61    public static final String CONFIG_ALIAS_ENABLED = "aliasEnabled";
62    public static final String CONFIG_ALLOW_ATTACH_AUDIO = "allowAttachAudio";
63    // If CONFIG_ENABLE_MULTIPART_SMS is true, long sms messages are always sent as multi-part sms
64    // messages, with no checked limit on the number of segments.
65    // If CONFIG_ENABLE_MULTIPART_SMS is false, then as soon as the user types a message longer
66    // than a single segment (i.e. 140 chars), then the message will turn into and be sent
67    // as an mms message or separate, independent SMS messages
68    // (which is dependent on CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES flag).
69    // This feature exists for carriers that don't support multi-part sms's.
70    public static final String CONFIG_ENABLE_MULTIPART_SMS = "enableMultipartSMS";
71    public static final String CONFIG_ENABLE_SMS_DELIVERY_REPORTS = "enableSMSDeliveryReports";
72    // If CONFIG_ENABLE_GROUP_MMS is true, a message with multiple recipients,
73    // regardless of contents, will be sent as a single MMS message with multiple "TO" fields set
74    // for each recipient.
75    // If CONFIG_ENABLE_GROUP_MMS is false, the group MMS setting/preference will be hidden
76    // in the settings activity.
77    public static final String CONFIG_ENABLE_GROUP_MMS = "enableGroupMms";
78    // If this is true, then we should read the content_disposition field of an MMS part
79    // Check wap-230-wsp-20010705-a.pdf, chapter 8.4.2.21
80    // Most carriers support it except Sprint.
81    // There is a system resource defining it:
82    // com.android.internal.R.bool.config_mms_content_disposition_support.
83    // But Shem can not read it. Add here so that we can configure for different carriers.
84    public static final String CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION =
85            "supportMmsContentDisposition";
86    // if true, show the cell broadcast (amber alert) in the SMS settings. Some carriers
87    // don't want this shown.
88    public static final String CONFIG_CELL_BROADCAST_APP_LINKS = "config_cellBroadcastAppLinks";
89    // If this is true, we will send multipart SMS as separate SMS messages
90    public static final String CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES =
91            "sendMultipartSmsAsSeparateMessages";
92    // FLAG(ywen): the following two is not supported yet.
93    public static final String CONFIG_ENABLE_MMS_READ_REPORTS = "enableMMSReadReports";
94    public static final String CONFIG_ENABLE_MMS_DELIVERY_REPORTS = "enableMMSDeliveryReports";
95    // Bouygues Telecom (20820) MMSC does not support "charset" with "Content-Type" header
96    // It would fail and return 500. See b/18604507
97    // If this is false, then we don't add "charset" to "Content-Type"
98    public static final String CONFIG_SUPPORT_HTTP_CHARSET_HEADER = "supportHttpCharsetHeader";
99    public static final String CONFIG_MAX_MESSAGE_SIZE = "maxMessageSize"; // in bytes
100    public static final String CONFIG_MAX_IMAGE_HEIGHT = "maxImageHeight"; // in pixels
101    public static final String CONFIG_MAX_IMAGE_WIDTH = "maxImageWidth"; // in pixels
102    public static final String CONFIG_RECIPIENT_LIMIT = "recipientLimit";
103    public static final String CONFIG_HTTP_SOCKET_TIMEOUT = "httpSocketTimeout";
104    public static final String CONFIG_ALIAS_MIN_CHARS = "aliasMinChars";
105    public static final String CONFIG_ALIAS_MAX_CHARS = "aliasMaxChars";
106    // If CONFIG_ENABLE_MULTIPART_SMS is true and CONFIG_SMS_TO_MMS_TEXT_THRESHOLD > 1,
107    // then multi-part SMS messages will be converted into a single mms message.
108    // For example, if the mms_config.xml file specifies <int name="smsToMmsTextThreshold">4</int>,
109    // then on the 5th sms segment, the message will be converted to an mms.
110    public static final String CONFIG_SMS_TO_MMS_TEXT_THRESHOLD = "smsToMmsTextThreshold";
111    // LGU+ temporarily requires any SMS message longer than 80 bytes to be sent as MMS
112    // see b/12122333
113    public static final String CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD =
114            "smsToMmsTextLengthThreshold";
115    public static final String CONFIG_MAX_MESSAGE_TEXT_SIZE = "maxMessageTextSize";
116    // maximum number of characters allowed for mms subject
117    public static final String CONFIG_MAX_SUBJECT_LENGTH = "maxSubjectLength";
118    public static final String CONFIG_UA_PROF_TAG_NAME = "uaProfTagName";
119    public static final String CONFIG_USER_AGENT = "userAgent";
120    public static final String CONFIG_UA_PROF_URL = "uaProfUrl";
121    public static final String CONFIG_HTTP_PARAMS = "httpParams";
122    // Email gateway alias support, including the master switch and different rules
123    public static final String CONFIG_EMAIL_GATEWAY_NUMBER = "emailGatewayNumber";
124    // String to append to the NAI header, e.g. ":pcs"
125    public static final String CONFIG_NAI_SUFFIX = "naiSuffix";
126
127    /*
128     * Key types
129     */
130    public static final String KEY_TYPE_INT = "int";
131    public static final String KEY_TYPE_BOOL = "bool";
132    public static final String KEY_TYPE_STRING = "string";
133
134    /*
135     * Macro names
136     */
137    // The raw phone number from TelephonyManager.getLine1Number
138    public static final String MACRO_LINE1 = "LINE1";
139    // The phone number without country code
140    public static final String MACRO_LINE1NOCOUNTRYCODE = "LINE1NOCOUNTRYCODE";
141    // NAI (Network Access Identifier), used by Sprint for authentication
142    public static final String MACRO_NAI = "NAI";
143
144    // Default values. This is read-only. Don't write into it.
145    // This provides the info on valid keys, their types and default values
146    private static final Map<String, Object> DEFAULTS = new ConcurrentHashMap<String, Object>();
147    static {
148        DEFAULTS.put(CONFIG_ENABLED_MMS, Boolean.valueOf(true));
149        DEFAULTS.put(CONFIG_ENABLED_TRANS_ID, Boolean.valueOf(false));
150        DEFAULTS.put(CONFIG_ENABLED_NOTIFY_WAP_MMSC, Boolean.valueOf(false));
151        DEFAULTS.put(CONFIG_ALIAS_ENABLED, Boolean.valueOf(false));
152        DEFAULTS.put(CONFIG_ALLOW_ATTACH_AUDIO, Boolean.valueOf(true));
153        DEFAULTS.put(CONFIG_ENABLE_MULTIPART_SMS, Boolean.valueOf(true));
154        DEFAULTS.put(CONFIG_ENABLE_SMS_DELIVERY_REPORTS, Boolean.valueOf(true));
155        DEFAULTS.put(CONFIG_ENABLE_GROUP_MMS, Boolean.valueOf(true));
156        DEFAULTS.put(CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION, Boolean.valueOf(true));
157        DEFAULTS.put(CONFIG_CELL_BROADCAST_APP_LINKS, Boolean.valueOf(true));
158        DEFAULTS.put(CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES, Boolean.valueOf(false));
159        DEFAULTS.put(CONFIG_ENABLE_MMS_READ_REPORTS, Boolean.valueOf(false));
160        DEFAULTS.put(CONFIG_ENABLE_MMS_DELIVERY_REPORTS, Boolean.valueOf(false));
161        DEFAULTS.put(CONFIG_SUPPORT_HTTP_CHARSET_HEADER, Boolean.valueOf(false));
162        DEFAULTS.put(CONFIG_MAX_MESSAGE_SIZE, Integer.valueOf(300 * 1024));
163        DEFAULTS.put(CONFIG_MAX_IMAGE_HEIGHT, Integer.valueOf(MAX_IMAGE_HEIGHT));
164        DEFAULTS.put(CONFIG_MAX_IMAGE_WIDTH, Integer.valueOf(MAX_IMAGE_WIDTH));
165        DEFAULTS.put(CONFIG_RECIPIENT_LIMIT, Integer.valueOf(Integer.MAX_VALUE));
166        DEFAULTS.put(CONFIG_HTTP_SOCKET_TIMEOUT, Integer.valueOf(60 * 1000));
167        DEFAULTS.put(CONFIG_ALIAS_MIN_CHARS, Integer.valueOf(2));
168        DEFAULTS.put(CONFIG_ALIAS_MAX_CHARS, Integer.valueOf(48));
169        DEFAULTS.put(CONFIG_SMS_TO_MMS_TEXT_THRESHOLD, Integer.valueOf(-1));
170        DEFAULTS.put(CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD, Integer.valueOf(-1));
171        DEFAULTS.put(CONFIG_MAX_MESSAGE_TEXT_SIZE, Integer.valueOf(-1));
172        DEFAULTS.put(CONFIG_MAX_SUBJECT_LENGTH, Integer.valueOf(40));
173        DEFAULTS.put(CONFIG_UA_PROF_TAG_NAME, DEFAULT_HTTP_KEY_X_WAP_PROFILE);
174        DEFAULTS.put(CONFIG_USER_AGENT, "");
175        DEFAULTS.put(CONFIG_UA_PROF_URL, "");
176        DEFAULTS.put(CONFIG_HTTP_PARAMS, "");
177        DEFAULTS.put(CONFIG_EMAIL_GATEWAY_NUMBER, "");
178        DEFAULTS.put(CONFIG_NAI_SUFFIX, "");
179    }
180
181    private final int mSubId;
182
183    /**
184     * This class manages a cached copy of current MMS configuration key values for a particular
185     * subscription id. (See the {@link android.telephony.SubscriptionManager}).
186     *
187     * @param context Context of the particular subscription to load. The context's mcc/mnc
188     * should be set to that of the subscription id
189     * @param subId Subscription id of the mcc/mnc in the context
190     */
191    public MmsConfig(Context context, int subId) {
192        mSubId = subId;
193        // Load defaults
194        mKeyValues.clear();
195        mKeyValues.putAll(DEFAULTS);
196        // Load User-Agent and UA profile URL settings
197        loadDeviceUaSettings(context);
198        Log.v(TAG, "MmsConfig: mUserAgent=" + mUserAgent + ", mUaProfUrl=" + mUaProfUrl);
199        // Load mms_config.xml resource overlays
200        loadFromResources(context);
201        Log.v(TAG, "MmsConfig: all settings -- " + mKeyValues);
202    }
203
204    /**
205     * Return the subscription ID associated with this MmsConfig
206     *
207     * @return subId the subId associated with this MmsConfig
208     */
209    public int getSubId() {
210        return mSubId;
211    }
212
213    /**
214     * Check a key and its type match the predefined keys and corresponding types
215     *
216     * @param key
217     * @param type Including "int" "bool" and "string"
218     * @return True if key and type both matches and false otherwise
219     */
220    public static boolean isValidKey(String key, String type) {
221        if (!TextUtils.isEmpty(key) && DEFAULTS.containsKey(key)) {
222            Object defVal = DEFAULTS.get(key);
223            Class<?> valueType = defVal != null ? defVal.getClass() : String.class;
224            if (KEY_TYPE_INT.equals(type)) {
225                return valueType == Integer.class;
226            } else if (KEY_TYPE_BOOL.equals(type)) {
227                return valueType == Boolean.class;
228            } else if (KEY_TYPE_STRING.equals(type)) {
229                return valueType == String.class;
230            }
231        }
232        return false;
233    }
234
235    /**
236     * Check a key and its type match the predefined keys and corresponding types
237     *
238     * @param key The key of the config
239     * @param value The value of the config
240     * @return True if key and type both matches and false otherwise
241     */
242    public static boolean isValidValue(String key, Object value) {
243        if (!TextUtils.isEmpty(key) && DEFAULTS.containsKey(key)) {
244            Object defVal = DEFAULTS.get(key);
245            Class<?> valueType = defVal != null ? defVal.getClass() : String.class;
246            return value.getClass().equals(valueType);
247        }
248        return false;
249    }
250
251    private String mUserAgent = null;
252    private String mUaProfUrl = null;
253
254    // The current values
255    private final Map<String, Object> mKeyValues = new ConcurrentHashMap<String, Object>();
256
257    /**
258     * Get a config value by its type
259     *
260     * @param key The key of the config
261     * @param type The type of the config value
262     * @return The expected typed value or null if no match
263     */
264    public Object getValueAsType(String key, String type) {
265        if (isValidKey(key, type)) {
266            return mKeyValues.get(key);
267        }
268        return null;
269    }
270
271    public Bundle getCarrierConfigValues() {
272        final Bundle bundle = new Bundle();
273        final Iterator<Map.Entry<String, Object>> iter = mKeyValues.entrySet().iterator();
274        while(iter.hasNext()) {
275            final Map.Entry<String, Object> entry = iter.next();
276            final String key = entry.getKey();
277            final Object val = entry.getValue();
278            Class<?> valueType =  val != null ? val.getClass() : String.class;
279            if (valueType == Integer.class) {
280                bundle.putInt(key, (Integer)val);
281            } else if (valueType == Boolean.class) {
282                bundle.putBoolean(key, (Boolean)val);
283            } else if (valueType == String.class) {
284                bundle.putString(key, (String)val);
285            }
286        }
287        return bundle;
288    }
289
290    private String getNullableStringValue(String key) {
291        final Object value = mKeyValues.get(key);
292        if (value != null) {
293            return (String) value;
294        }
295        return null;
296    }
297
298    private void update(String key, String value, String type) {
299        try {
300            if (KEY_TYPE_INT.equals(type)) {
301                mKeyValues.put(key, Integer.parseInt(value));
302            } else if (KEY_TYPE_BOOL.equals(type)) {
303                mKeyValues.put(key, Boolean.parseBoolean(value));
304            } else if (KEY_TYPE_STRING.equals(type)){
305                mKeyValues.put(key, value);
306            }
307        } catch (NumberFormatException e) {
308            Log.e(TAG, "MmsConfig.update: invalid " + key + "," + value + "," + type);
309        }
310    }
311
312    private void loadDeviceUaSettings(Context context) {
313        // load the MMS User agent and UaProfUrl from TelephonyManager APIs
314        final TelephonyManager telephonyManager =
315                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
316        mUserAgent = telephonyManager.getMmsUserAgent();
317        mUaProfUrl = telephonyManager.getMmsUAProfUrl();
318    }
319
320    private void loadFromResources(Context context) {
321        Log.d(TAG, "MmsConfig.loadFromResources");
322        final XmlResourceParser parser = context.getResources().getXml(R.xml.mms_config);
323        final MmsConfigXmlProcessor processor = MmsConfigXmlProcessor.get(parser);
324        processor.setMmsConfigHandler(new MmsConfigXmlProcessor.MmsConfigHandler() {
325            @Override
326            public void process(String key, String value, String type) {
327                update(key, value, type);
328            }
329        });
330        try {
331            processor.process();
332        } finally {
333            parser.close();
334        }
335    }
336
337    /**
338     * This class returns corresponding MmsConfig values which can be overridden by
339     * externally provided values.
340     */
341    public static class Overridden {
342        // The base MmsConfig
343        private final MmsConfig mBase;
344        // The overridden values
345        private final Bundle mOverrides;
346
347        public Overridden(MmsConfig base, Bundle overrides) {
348            mBase = base;
349            mOverrides = overrides;
350        }
351
352        private int getInt(String key) {
353            final Integer def = (Integer) mBase.mKeyValues.get(key);
354            return mOverrides != null ? mOverrides.getInt(key, def) : def;
355        }
356
357        private boolean getBoolean(String key) {
358            final Boolean def = (Boolean) mBase.mKeyValues.get(key);
359            return mOverrides != null ? mOverrides.getBoolean(key, def) : def;
360        }
361
362        private String getString(String key) {
363            if (mOverrides != null && mOverrides.containsKey(key)) {
364                return mOverrides.getString(key);
365            }
366            return mBase.getNullableStringValue(key);
367        }
368
369        public int getSmsToMmsTextThreshold() {
370            return getInt(CONFIG_SMS_TO_MMS_TEXT_THRESHOLD);
371        }
372
373        public int getSmsToMmsTextLengthThreshold() {
374            return getInt(CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD);
375        }
376
377        public boolean getMmsEnabled() {
378            return getBoolean(CONFIG_ENABLED_MMS);
379        }
380
381        public int getMaxMessageSize() {
382            return getInt(CONFIG_MAX_MESSAGE_SIZE);
383        }
384
385        public boolean getTransIdEnabled() {
386            return getBoolean(CONFIG_ENABLED_TRANS_ID);
387        }
388
389        public String getUserAgent() {
390            if (mOverrides != null && mOverrides.containsKey(CONFIG_USER_AGENT)) {
391                return mOverrides.getString(CONFIG_USER_AGENT);
392            }
393            return !TextUtils.isEmpty(mBase.mUserAgent) ?
394                    mBase.mUserAgent : mBase.getNullableStringValue(CONFIG_USER_AGENT);
395        }
396
397        public String getUaProfTagName() {
398            return getString(CONFIG_UA_PROF_TAG_NAME);
399        }
400
401        public String getUaProfUrl() {
402            if (mOverrides != null && mOverrides.containsKey(CONFIG_UA_PROF_URL)) {
403                return mOverrides.getString(CONFIG_UA_PROF_URL);
404            }
405            return !TextUtils.isEmpty(mBase.mUaProfUrl) ?
406                    mBase.mUaProfUrl : mBase.getNullableStringValue(CONFIG_UA_PROF_URL);
407        }
408
409        public String getHttpParams() {
410            return getString(CONFIG_HTTP_PARAMS);
411        }
412
413        public String getEmailGateway() {
414            return getString(CONFIG_EMAIL_GATEWAY_NUMBER);
415        }
416
417        public int getMaxImageHeight() {
418            return getInt(CONFIG_MAX_IMAGE_HEIGHT);
419        }
420
421        public int getMaxImageWidth() {
422            return getInt(CONFIG_MAX_IMAGE_WIDTH);
423        }
424
425        public int getRecipientLimit() {
426            final int limit = getInt(CONFIG_RECIPIENT_LIMIT);
427            return limit < 0 ? Integer.MAX_VALUE : limit;
428        }
429
430        public int getMaxTextLimit() {
431            final int max = getInt(CONFIG_MAX_MESSAGE_TEXT_SIZE);
432            return max > -1 ? max : MAX_TEXT_LENGTH;
433        }
434
435        public int getHttpSocketTimeout() {
436            return getInt(CONFIG_HTTP_SOCKET_TIMEOUT);
437        }
438
439        public boolean getMultipartSmsEnabled() {
440            return getBoolean(CONFIG_ENABLE_MULTIPART_SMS);
441        }
442
443        public boolean getSendMultipartSmsAsSeparateMessages() {
444            return getBoolean(CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES);
445        }
446
447        public boolean getSMSDeliveryReportsEnabled() {
448            return getBoolean(CONFIG_ENABLE_SMS_DELIVERY_REPORTS);
449        }
450
451        public boolean getNotifyWapMMSC() {
452            return getBoolean(CONFIG_ENABLED_NOTIFY_WAP_MMSC);
453        }
454
455        public boolean isAliasEnabled() {
456            return getBoolean(CONFIG_ALIAS_ENABLED);
457        }
458
459        public int getAliasMinChars() {
460            return getInt(CONFIG_ALIAS_MIN_CHARS);
461        }
462
463        public int getAliasMaxChars() {
464            return getInt(CONFIG_ALIAS_MAX_CHARS);
465        }
466
467        public boolean getAllowAttachAudio() {
468            return getBoolean(CONFIG_ALLOW_ATTACH_AUDIO);
469        }
470
471        public int getMaxSubjectLength() {
472            return getInt(CONFIG_MAX_SUBJECT_LENGTH);
473        }
474
475        public boolean getGroupMmsEnabled() {
476            return getBoolean(CONFIG_ENABLE_GROUP_MMS);
477        }
478
479        public boolean getSupportMmsContentDisposition() {
480            return getBoolean(CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION);
481        }
482
483        public boolean getShowCellBroadcast() {
484            return getBoolean(CONFIG_CELL_BROADCAST_APP_LINKS);
485        }
486
487        public String getNaiSuffix() {
488            return getString(CONFIG_NAI_SUFFIX);
489        }
490
491        public boolean isMmsReadReportsEnabled() {
492            return getBoolean(CONFIG_ENABLE_MMS_READ_REPORTS);
493        }
494
495        public boolean isMmsDeliveryReportsEnabled() {
496            return getBoolean(CONFIG_ENABLE_MMS_DELIVERY_REPORTS);
497        }
498
499        public boolean getSupportHttpCharsetHeader() {
500            return getBoolean(CONFIG_SUPPORT_HTTP_CHARSET_HEADER);
501        }
502
503        /**
504         * Return the HTTP param macro value.
505         * Example: LINE1 returns the phone number, etc.
506         *
507         * @param macro The macro name
508         * @return The value of the defined macro
509         */
510        public String getHttpParamMacro(Context context, String macro) {
511            if (MACRO_LINE1.equals(macro)) {
512                return getLine1(context, mBase.getSubId());
513            } else if (MACRO_LINE1NOCOUNTRYCODE.equals(macro)) {
514                return getLine1NoCountryCode(context, mBase.getSubId());
515            } else if (MACRO_NAI.equals(macro)) {
516                return getNai(context, mBase.getSubId());
517            }
518            return null;
519        }
520
521        /**
522         * @return the phone number
523         */
524        private static String getLine1(Context context, int subId) {
525            final TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
526                    Context.TELEPHONY_SERVICE);
527            return telephonyManager.getLine1NumberForSubscriber(subId);
528        }
529
530        private static String getLine1NoCountryCode(Context context, int subId) {
531            final TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
532                    Context.TELEPHONY_SERVICE);
533            return PhoneUtils.getNationalNumber(
534                    telephonyManager,
535                    subId,
536                    telephonyManager.getLine1NumberForSubscriber(subId));
537        }
538
539        /**
540         * @return the NAI (Network Access Identifier) from SystemProperties
541         */
542        private String getNai(Context context, int subId) {
543            final TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
544                    Context.TELEPHONY_SERVICE);
545            String nai = telephonyManager.getNai(SubscriptionManager.getSlotId(subId));
546            if (Log.isLoggable(TAG, Log.VERBOSE)) {
547                Log.v(TAG, "MmsConfig.getNai: nai=" + nai);
548            }
549
550            if (!TextUtils.isEmpty(nai)) {
551                String naiSuffix = getNaiSuffix();
552                if (!TextUtils.isEmpty(naiSuffix)) {
553                    nai = nai + naiSuffix;
554                }
555                byte[] encoded = null;
556                try {
557                    encoded = Base64.encode(nai.getBytes("UTF-8"), Base64.NO_WRAP);
558                } catch (UnsupportedEncodingException e) {
559                    encoded = Base64.encode(nai.getBytes(), Base64.NO_WRAP);
560                }
561                try {
562                    nai = new String(encoded, "UTF-8");
563                } catch (UnsupportedEncodingException e) {
564                    nai = new String(encoded);
565                }
566            }
567            return nai;
568        }
569    }
570}
571