Home | History | Annotate | Download | only in service
      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.SubscriptionInfo;
     25 import android.telephony.SubscriptionManager;
     26 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
     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 
     35 /**
     36  * This class manages cached copies of all the MMS configuration for each subscription ID.
     37  * A subscription ID loosely corresponds to a particular SIM. See the
     38  * {@link android.telephony.SubscriptionManager} for more details.
     39  *
     40  */
     41 public class MmsConfigManager {
     42     private static final String TAG = MmsService.TAG;
     43 
     44     private static volatile MmsConfigManager sInstance = new MmsConfigManager();
     45 
     46     public static MmsConfigManager getInstance() {
     47         return sInstance;
     48     }
     49 
     50     // Map the various subIds to their corresponding MmsConfigs.
     51     private final Map<Integer, MmsConfig> mSubIdConfigMap = new ArrayMap<Integer, MmsConfig>();
     52     private Context mContext;
     53     private SubscriptionManager mSubscriptionManager;
     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(IccCardConstants.INTENT_VALUE_ICC_LOADED)) {
     67                 loadInBackground();
     68             }
     69         }
     70     };
     71 
     72     private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
     73             new OnSubscriptionsChangedListener() {
     74         @Override
     75         public void onSubscriptionsChanged() {
     76             loadInBackground();
     77         }
     78     };
     79 
     80 
     81     public void init(final Context context) {
     82         mContext = context;
     83         mSubscriptionManager = SubscriptionManager.from(context);
     84 
     85         // TODO: When this object "finishes" we should unregister.
     86         IntentFilter intentFilterLoaded =
     87                 new IntentFilter(IccCardConstants.INTENT_VALUE_ICC_LOADED);
     88         context.registerReceiver(mReceiver, intentFilterLoaded);
     89 
     90         // TODO: When this object "finishes" we should unregister by invoking
     91         // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener);
     92         // This is not strictly necessary because it will be unregistered if the
     93         // notification fails but it is good form.
     94 
     95         // Register for SubscriptionInfo list changes which is guaranteed
     96         // to invoke onSubscriptionsChanged the first time.
     97         SubscriptionManager.from(mContext).addOnSubscriptionsChangedListener(
     98                 mOnSubscriptionsChangedListener);
     99     }
    100 
    101     private void loadInBackground() {
    102         // TODO (ywen) - AsyncTask to avoid creating a new thread?
    103         new Thread() {
    104             @Override
    105             public void run() {
    106                 Configuration configuration = mContext.getResources().getConfiguration();
    107                 // Always put the mnc/mcc in the log so we can tell which mms_config.xml
    108                 // was loaded.
    109                 Log.i(TAG, "MmsConfigManager.loadInBackground(): mcc/mnc: " +
    110                         configuration.mcc + "/" + configuration.mnc);
    111                 load(mContext);
    112             }
    113         }.start();
    114     }
    115 
    116     /**
    117      * Find and return the MmsConfig for a particular subscription id.
    118      *
    119      * @param subId Subscription id of the desired MmsConfig
    120      * @return MmsConfig for the particular subscription id. This function can return null if
    121      *         the MmsConfig cannot be found or if this function is called before the
    122      *         TelephonyManager has setup the SIMs or if loadInBackground is still spawning a
    123      *         thread after a recent LISTEN_SUBSCRIPTION_INFO_LIST_CHANGED event.
    124      */
    125     public MmsConfig getMmsConfigBySubId(int subId) {
    126         MmsConfig mmsConfig;
    127         synchronized(mSubIdConfigMap) {
    128             mmsConfig = mSubIdConfigMap.get(subId);
    129         }
    130         Log.i(TAG, "getMmsConfigBySubId -- for sub: " + subId + " mmsConfig: " + mmsConfig);
    131         return mmsConfig;
    132     }
    133 
    134     /**
    135      * This function goes through all the activated subscription ids (the actual SIMs in the
    136      * device), builds a context with that SIM's mcc/mnc and loads the appropriate mms_config.xml
    137      * file via the ResourceManager. With single-SIM devices, there will be a single subId.
    138      *
    139      */
    140     private void load(Context context) {
    141         List<SubscriptionInfo> subs = mSubscriptionManager.getActiveSubscriptionInfoList();
    142         if (subs == null || subs.size() < 1) {
    143             Log.e(TAG, "MmsConfigManager.load -- empty getActiveSubInfoList");
    144             return;
    145         }
    146         // Load all the mms_config.xml files in a separate map and then swap with the
    147         // real map at the end so we don't block anyone sync'd on the real map.
    148         final Map<Integer, MmsConfig> newConfigMap = new ArrayMap<Integer, MmsConfig>();
    149         for (SubscriptionInfo sub : subs) {
    150             Configuration configuration = new Configuration();
    151             if (sub.getMcc() == 0 && sub.getMnc() == 0) {
    152                 Configuration config = mContext.getResources().getConfiguration();
    153                 configuration.mcc = config.mcc;
    154                 configuration.mnc = config.mnc;
    155                 Log.i(TAG, "MmsConfigManager.load -- no mcc/mnc for sub: " + sub +
    156                         " using mcc/mnc from main context: " + configuration.mcc + "/" +
    157                                 configuration.mnc);
    158             } else {
    159                 Log.i(TAG, "MmsConfigManager.load -- mcc/mnc for sub: " + sub);
    160 
    161                 configuration.mcc = sub.getMcc();
    162                 configuration.mnc = sub.getMnc();
    163             }
    164             Context subContext = context.createConfigurationContext(configuration);
    165 
    166             int subId = sub.getSubscriptionId();
    167             newConfigMap.put(subId, new MmsConfig(subContext, subId));
    168         }
    169         synchronized(mSubIdConfigMap) {
    170             mSubIdConfigMap.clear();
    171             mSubIdConfigMap.putAll(newConfigMap);
    172         }
    173     }
    174 
    175 }
    176