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.os.Bundle;
     25 import android.os.PersistableBundle;
     26 import android.telephony.CarrierConfigManager;
     27 import android.telephony.SmsManager;
     28 import android.telephony.SubscriptionInfo;
     29 import android.telephony.SubscriptionManager;
     30 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
     31 import android.util.ArrayMap;
     32 
     33 import com.android.internal.telephony.IccCardConstants;
     34 
     35 import java.util.List;
     36 import java.util.Map;
     37 
     38 /**
     39  * This class manages cached copies of all the MMS configuration for each subscription ID.
     40  * A subscription ID loosely corresponds to a particular SIM. See the
     41  * {@link android.telephony.SubscriptionManager} for more details.
     42  *
     43  */
     44 public class MmsConfigManager {
     45     private static volatile MmsConfigManager sInstance = new MmsConfigManager();
     46 
     47     public static MmsConfigManager getInstance() {
     48         return sInstance;
     49     }
     50 
     51     // Map the various subIds to their corresponding MmsConfigs.
     52     private final Map<Integer, Bundle> mSubIdConfigMap = new ArrayMap<Integer, Bundle>();
     53     private Context mContext;
     54     private SubscriptionManager mSubscriptionManager;
     55 
     56     /**
     57      * This receiver listens for changes made to SubInfoRecords and for a broadcast telling us
     58      * the TelephonyManager has loaded the information needed in order to get the mcc/mnc's for
     59      * each subscription Id. When either of these broadcasts are received, we rebuild the
     60      * MmsConfig table.
     61      *
     62      */
     63     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
     64         public void onReceive(Context context, Intent intent) {
     65             String action = intent.getAction();
     66             LogUtil.i("MmsConfigManager receiver action: " + action);
     67             if (action.equals(IccCardConstants.INTENT_VALUE_ICC_LOADED)) {
     68                 loadInBackground();
     69             }
     70         }
     71     };
     72 
     73     private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
     74             new OnSubscriptionsChangedListener() {
     75         @Override
     76         public void onSubscriptionsChanged() {
     77             loadInBackground();
     78         }
     79     };
     80 
     81 
     82     public void init(final Context context) {
     83         mContext = context;
     84         mSubscriptionManager = SubscriptionManager.from(context);
     85 
     86         // TODO: When this object "finishes" we should unregister.
     87         final IntentFilter intentFilterLoaded =
     88                 new IntentFilter(IccCardConstants.INTENT_VALUE_ICC_LOADED);
     89         context.registerReceiver(mReceiver, intentFilterLoaded);
     90 
     91         // TODO: When this object "finishes" we should unregister by invoking
     92         // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener);
     93         // This is not strictly necessary because it will be unregistered if the
     94         // notification fails but it is good form.
     95 
     96         // Register for SubscriptionInfo list changes which is guaranteed
     97         // to invoke onSubscriptionsChanged the first time.
     98         SubscriptionManager.from(mContext).addOnSubscriptionsChangedListener(
     99                 mOnSubscriptionsChangedListener);
    100     }
    101 
    102     private void loadInBackground() {
    103         // TODO (ywen) - AsyncTask to avoid creating a new thread?
    104         new Thread() {
    105             @Override
    106             public void run() {
    107                 Configuration configuration = mContext.getResources().getConfiguration();
    108                 // Always put the mnc/mcc in the log so we can tell which mms_config.xml
    109                 // was loaded.
    110                 LogUtil.i("MmsConfigManager loads in background mcc/mnc: " +
    111                         configuration.mcc + "/" + configuration.mnc);
    112                 load(mContext);
    113             }
    114         }.start();
    115     }
    116 
    117     /**
    118      * Find and return the MMS config for a particular subscription id.
    119      *
    120      * @param subId Subscription id of the desired MMS config bundle
    121      * @return MMS config bundle for the particular subscription id. This function can return null
    122      *         if the MMS config cannot be found or if this function is called before the
    123      *         TelephonyManager has set up the SIMs, or if loadInBackground is still spawning a
    124      *         thread after a recent LISTEN_SUBSCRIPTION_INFO_LIST_CHANGED event.
    125      */
    126     public Bundle getMmsConfigBySubId(int subId) {
    127         Bundle mmsConfig;
    128         synchronized(mSubIdConfigMap) {
    129             mmsConfig = mSubIdConfigMap.get(subId);
    130         }
    131         LogUtil.i("mms config for sub " + subId + ": " + mmsConfig);
    132         // Return a copy so that callers can mutate it.
    133         if (mmsConfig != null) {
    134           return new Bundle(mmsConfig);
    135         }
    136         return null;
    137     }
    138 
    139     /**
    140      * This loads the MMS config for each active subscription.
    141      *
    142      * MMS config is fetched from CarrierConfigManager and filtered to only include MMS config
    143      * variables. The resulting bundles are stored in mSubIdConfigMap.
    144      */
    145     private void load(Context context) {
    146         List<SubscriptionInfo> subs = mSubscriptionManager.getActiveSubscriptionInfoList();
    147         if (subs == null || subs.size() < 1) {
    148             LogUtil.e(" Failed to load mms config: empty getActiveSubInfoList");
    149             return;
    150         }
    151         // Load all the config bundles into a new map and then swap it with the real map to avoid
    152         // blocking.
    153         final Map<Integer, Bundle> newConfigMap = new ArrayMap<Integer, Bundle>();
    154         final CarrierConfigManager configManager =
    155                 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
    156         for (SubscriptionInfo sub : subs) {
    157             final int subId = sub.getSubscriptionId();
    158             PersistableBundle config = configManager.getConfigForSubId(subId);
    159             newConfigMap.put(subId, SmsManager.getMmsConfig(config));
    160         }
    161         synchronized(mSubIdConfigMap) {
    162             mSubIdConfigMap.clear();
    163             mSubIdConfigMap.putAll(newConfigMap);
    164         }
    165     }
    166 
    167 }
    168