1 /* 2 * Copyright (C) 2015 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.messaging.sms; 18 19 import android.content.Context; 20 import android.content.res.Configuration; 21 import android.content.res.Resources; 22 import android.content.res.XmlResourceParser; 23 import android.os.Bundle; 24 import androidx.appcompat.mms.CarrierConfigValuesLoader; 25 import android.util.SparseArray; 26 27 import com.android.messaging.R; 28 import com.android.messaging.util.LogUtil; 29 import com.android.messaging.util.OsUtil; 30 import com.android.messaging.util.PhoneUtils; 31 32 /** 33 * Carrier configuration loader 34 * 35 * Loader tries to load from resources. If there is MMS API available, also 36 * load from system. 37 */ 38 public class BugleCarrierConfigValuesLoader implements CarrierConfigValuesLoader { 39 /* 40 * Key types 41 */ 42 public static final String KEY_TYPE_INT = "int"; 43 public static final String KEY_TYPE_BOOL = "bool"; 44 public static final String KEY_TYPE_STRING = "string"; 45 46 private final Context mContext; 47 48 // Cached values for subIds 49 private final SparseArray<Bundle> mValuesCache; 50 BugleCarrierConfigValuesLoader(final Context context)51 public BugleCarrierConfigValuesLoader(final Context context) { 52 mContext = context; 53 mValuesCache = new SparseArray<>(); 54 } 55 56 @Override get(int subId)57 public Bundle get(int subId) { 58 subId = PhoneUtils.getDefault().getEffectiveSubId(subId); 59 Bundle values; 60 String loadSource = null; 61 synchronized (this) { 62 values = mValuesCache.get(subId); 63 if (values == null) { 64 values = new Bundle(); 65 mValuesCache.put(subId, values); 66 loadSource = loadLocked(subId, values); 67 } 68 } 69 if (loadSource != null) { 70 LogUtil.i(LogUtil.BUGLE_TAG, "Carrier configs loaded: " + values 71 + " from " + loadSource + " for subId=" + subId); 72 } 73 return values; 74 } 75 76 /** 77 * Clear the cache for reloading 78 */ reset()79 public void reset() { 80 synchronized (this) { 81 mValuesCache.clear(); 82 } 83 } 84 85 /** 86 * Loading carrier config values 87 * 88 * @param subId which SIM to load for 89 * @param values the result to add to 90 * @return the source of the config, could be "resources" or "resources+system" 91 */ loadLocked(final int subId, final Bundle values)92 private String loadLocked(final int subId, final Bundle values) { 93 // Load from resources in earlier platform 94 loadFromResources(subId, values); 95 if (OsUtil.isAtLeastL()) { 96 // Load from system to override if system API exists 97 loadFromSystem(subId, values); 98 return "resources+system"; 99 } 100 return "resources"; 101 } 102 103 /** 104 * Load from system, using MMS API 105 * 106 * @param subId which SIM to load for 107 * @param values the result to add to 108 */ loadFromSystem(final int subId, final Bundle values)109 private static void loadFromSystem(final int subId, final Bundle values) { 110 try { 111 final Bundle systemValues = 112 PhoneUtils.get(subId).getSmsManager().getCarrierConfigValues(); 113 if (systemValues != null) { 114 values.putAll(systemValues); 115 } 116 } catch (final Exception e) { 117 LogUtil.w(LogUtil.BUGLE_TAG, "Calling system getCarrierConfigValues exception", e); 118 } 119 } 120 121 /** 122 * Load from SIM-dependent resources 123 * 124 * @param subId which SIM to load for 125 * @param values the result to add to 126 */ loadFromResources(final int subId, final Bundle values)127 private void loadFromResources(final int subId, final Bundle values) { 128 // Get a subscription-dependent context for loading the mms_config.xml 129 final Context subContext = getSubDepContext(mContext, subId); 130 // Load and parse the XML 131 XmlResourceParser parser = null; 132 try { 133 parser = subContext.getResources().getXml(R.xml.mms_config); 134 final ApnsXmlProcessor processor = ApnsXmlProcessor.get(parser); 135 processor.setMmsConfigHandler(new ApnsXmlProcessor.MmsConfigHandler() { 136 @Override 137 public void process(final String mccMnc, final String key, final String value, 138 final String type) { 139 update(values, type, key, value); 140 } 141 }); 142 processor.process(); 143 } catch (final Resources.NotFoundException e) { 144 LogUtil.w(LogUtil.BUGLE_TAG, "Can not find mms_config.xml"); 145 } finally { 146 if (parser != null) { 147 parser.close(); 148 } 149 } 150 } 151 152 /** 153 * Get a subscription's Context so we can load resources from it 154 * 155 * @param context the sub-independent Context 156 * @param subId the SIM's subId 157 * @return the sub-dependent Context 158 */ getSubDepContext(final Context context, final int subId)159 private static Context getSubDepContext(final Context context, final int subId) { 160 if (!OsUtil.isAtLeastL_MR1()) { 161 return context; 162 } 163 final int[] mccMnc = PhoneUtils.get(subId).getMccMnc(); 164 final int mcc = mccMnc[0]; 165 final int mnc = mccMnc[1]; 166 final Configuration subConfig = new Configuration(); 167 if (mcc == 0 && mnc == 0) { 168 Configuration config = context.getResources().getConfiguration(); 169 subConfig.mcc = config.mcc; 170 subConfig.mnc = config.mnc; 171 } else { 172 subConfig.mcc = mcc; 173 subConfig.mnc = mnc; 174 } 175 return context.createConfigurationContext(subConfig); 176 } 177 178 /** 179 * Add or update a carrier config key/value pair to the Bundle 180 * 181 * @param values the result Bundle to add to 182 * @param type the value type 183 * @param key the key 184 * @param value the value 185 */ update(final Bundle values, final String type, final String key, final String value)186 public static void update(final Bundle values, final String type, final String key, 187 final String value) { 188 try { 189 if (KEY_TYPE_INT.equals(type)) { 190 values.putInt(key, Integer.parseInt(value)); 191 } else if (KEY_TYPE_BOOL.equals(type)) { 192 values.putBoolean(key, Boolean.parseBoolean(value)); 193 } else if (KEY_TYPE_STRING.equals(type)){ 194 values.putString(key, value); 195 } 196 } catch (final NumberFormatException e) { 197 LogUtil.w(LogUtil.BUGLE_TAG, "Add carrier values: " 198 + "invalid " + key + "," + value + "," + type); 199 } 200 } 201 } 202