• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.mms.service;
18 
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.content.res.Configuration;
24 import android.telephony.SubInfoRecord;
25 import android.telephony.SubscriptionManager;
26 import android.text.TextUtils;
27 import android.util.ArrayMap;
28 import android.util.Log;
29 
30 import java.util.List;
31 import java.util.Map;
32 
33 import com.android.internal.telephony.IccCardConstants;
34 import com.android.internal.telephony.TelephonyIntents;
35 
36 /**
37  * This class manages cached copies of all the MMS configuration for each subscription ID.
38  * A subscription ID loosely corresponds to a particular SIM. See the
39  * {@link android.telephony.SubscriptionManager} for more details.
40  *
41  */
42 public class MmsConfigManager {
43     private static final String TAG = MmsService.TAG;
44 
45     private static volatile MmsConfigManager sInstance = new MmsConfigManager();
46 
getInstance()47     public static MmsConfigManager getInstance() {
48         return sInstance;
49     }
50 
51     // Map the various subIds to their corresponding MmsConfigs.
52     private final Map<Long, MmsConfig> mSubIdConfigMap = new ArrayMap<Long, MmsConfig>();
53     private Context mContext;
54 
55     /**
56      * This receiver listens for changes made to SubInfoRecords and for a broadcast telling us
57      * the TelephonyManager has loaded the information needed in order to get the mcc/mnc's for
58      * each subscription Id. When either of these broadcasts are received, we rebuild the
59      * MmsConfig table.
60      *
61      */
62     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
63         public void onReceive(Context context, Intent intent) {
64             String action = intent.getAction();
65             Log.i(TAG, "mReceiver action: " + action);
66             if (action.equals(TelephonyIntents.ACTION_SUBINFO_RECORD_UPDATED) ||
67                     action.equals(TelephonyIntents.ACTION_SUBINFO_CONTENT_CHANGE) ||
68                     action.equals(IccCardConstants.INTENT_VALUE_ICC_LOADED)) {
69                 loadInBackground();
70             }
71         }
72     };
73 
init(final Context context)74     public void init(final Context context) {
75         IntentFilter intentFilter =
76                 new IntentFilter(TelephonyIntents.ACTION_SUBINFO_RECORD_UPDATED);
77         context.registerReceiver(mReceiver, intentFilter);
78         IntentFilter intentFilterChange =
79                 new IntentFilter(TelephonyIntents.ACTION_SUBINFO_CONTENT_CHANGE);
80         context.registerReceiver(mReceiver, intentFilterChange);
81         IntentFilter intentFilterLoaded =
82                 new IntentFilter(IccCardConstants.INTENT_VALUE_ICC_LOADED);
83         context.registerReceiver(mReceiver, intentFilterLoaded);
84 
85         mContext = context;
86         loadInBackground();
87     }
88 
loadInBackground()89     private void loadInBackground() {
90         // TODO (ywen) - AsyncTask to avoid creating a new thread?
91         new Thread() {
92             @Override
93             public void run() {
94                 Configuration configuration = mContext.getResources().getConfiguration();
95                 // Always put the mnc/mcc in the log so we can tell which mms_config.xml
96                 // was loaded.
97                 Log.i(TAG, "MmsConfigManager.loadInBackground(): mcc/mnc: " +
98                         configuration.mcc + "/" + configuration.mnc);
99                 load(mContext);
100             }
101         }.start();
102     }
103 
104     /**
105      * Find and return the MmsConfig for a particular subscription id.
106      *
107      * @param subId Subscription id of the desired MmsConfig
108      * @return MmsConfig for the particular subscription id. This function can return null if
109      *         the MmsConfig cannot be found or if this function is called before the
110      *         TelephonyManager has setup the SIMs or if loadInBackground is still spawning a
111      *         thread after a recent ACTION_SUBINFO_RECORD_UPDATED event.
112      */
getMmsConfigBySubId(long subId)113     public MmsConfig getMmsConfigBySubId(long subId) {
114         MmsConfig mmsConfig;
115         synchronized(mSubIdConfigMap) {
116             mmsConfig = mSubIdConfigMap.get(subId);
117         }
118         Log.i(TAG, "getMmsConfigBySubId -- for sub: " + subId + " mmsConfig: " + mmsConfig);
119         return mmsConfig;
120     }
121 
122     /**
123      * This function goes through all the activated subscription ids (the actual SIMs in the
124      * device), builds a context with that SIM's mcc/mnc and loads the appropriate mms_config.xml
125      * file via the ResourceManager. With single-SIM devices, there will be a single subId.
126      *
127      */
load(Context context)128     private void load(Context context) {
129         List<SubInfoRecord> subs = SubscriptionManager.getActiveSubInfoList();
130         if (subs == null || subs.size() < 1) {
131             Log.e(TAG, "MmsConfigManager.load -- empty getActiveSubInfoList");
132             return;
133         }
134         // Load all the mms_config.xml files in a separate map and then swap with the
135         // real map at the end so we don't block anyone sync'd on the real map.
136         final Map<Long, MmsConfig> newConfigMap = new ArrayMap<Long, MmsConfig>();
137         for (SubInfoRecord sub : subs) {
138             Configuration configuration = new Configuration();
139             if (sub.mcc == 0 && sub.mnc == 0) {
140                 Configuration config = mContext.getResources().getConfiguration();
141                 configuration.mcc = config.mcc;
142                 configuration.mnc = config.mnc;
143                 Log.i(TAG, "MmsConfigManager.load -- no mcc/mnc for sub: " + sub +
144                         " using mcc/mnc from main context: " + configuration.mcc + "/" +
145                                 configuration.mnc);
146             } else {
147                 Log.i(TAG, "MmsConfigManager.load -- mcc/mnc for sub: " + sub);
148 
149                 configuration.mcc = sub.mcc;
150                 configuration.mnc = sub.mnc;
151             }
152             Context subContext = context.createConfigurationContext(configuration);
153 
154             newConfigMap.put(sub.subId, new MmsConfig(subContext, sub.subId));
155         }
156         synchronized(mSubIdConfigMap) {
157             mSubIdConfigMap.clear();
158             mSubIdConfigMap.putAll(newConfigMap);
159         }
160     }
161 
162 }
163