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.os.Bundle;
20 import androidx.appcompat.mms.CarrierConfigValuesLoader;
21 import android.telephony.SubscriptionInfo;
22 
23 import com.android.messaging.Factory;
24 import com.android.messaging.datamodel.data.ParticipantData;
25 import com.android.messaging.util.Assert;
26 import com.android.messaging.util.LogUtil;
27 import com.android.messaging.util.OsUtil;
28 import com.android.messaging.util.PhoneUtils;
29 import com.android.messaging.util.SafeAsyncTask;
30 import com.google.common.collect.Maps;
31 
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Set;
35 
36 /**
37  * MMS configuration.
38  *
39  * This is now a wrapper around the BugleCarrierConfigValuesLoader, which does
40  * the actual loading and stores the values in a Bundle. This class provides getter
41  * methods for values used in the app, which is easier to use than the raw loader
42  * class.
43  */
44 public class MmsConfig {
45     private static final String TAG = LogUtil.BUGLE_TAG;
46 
47     private static final int DEFAULT_MAX_TEXT_LENGTH = 2000;
48 
49     /*
50      * Key types
51      */
52     public static final String KEY_TYPE_INT = "int";
53     public static final String KEY_TYPE_BOOL = "bool";
54     public static final String KEY_TYPE_STRING = "string";
55 
56     private static final Map<String, String> sKeyTypeMap = Maps.newHashMap();
57     static {
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ENABLED_MMS, KEY_TYPE_BOOL)58         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ENABLED_MMS, KEY_TYPE_BOOL);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ENABLED_TRANS_ID, KEY_TYPE_BOOL)59         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ENABLED_TRANS_ID, KEY_TYPE_BOOL);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ENABLED_NOTIFY_WAP_MMSC, KEY_TYPE_BOOL)60         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ENABLED_NOTIFY_WAP_MMSC, KEY_TYPE_BOOL);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ALIAS_ENABLED, KEY_TYPE_BOOL)61         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ALIAS_ENABLED, KEY_TYPE_BOOL);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ALLOW_ATTACH_AUDIO, KEY_TYPE_BOOL)62         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ALLOW_ATTACH_AUDIO, KEY_TYPE_BOOL);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ENABLE_MULTIPART_SMS, KEY_TYPE_BOOL)63         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ENABLE_MULTIPART_SMS, KEY_TYPE_BOOL);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ENABLE_SMS_DELIVERY_REPORTS, KEY_TYPE_BOOL)64         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ENABLE_SMS_DELIVERY_REPORTS,
65                 KEY_TYPE_BOOL);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ENABLE_GROUP_MMS, KEY_TYPE_BOOL)66         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ENABLE_GROUP_MMS, KEY_TYPE_BOOL);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION, KEY_TYPE_BOOL)67         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION,
68                 KEY_TYPE_BOOL);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_CELL_BROADCAST_APP_LINKS, KEY_TYPE_BOOL)69         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_CELL_BROADCAST_APP_LINKS, KEY_TYPE_BOOL);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES, KEY_TYPE_BOOL)70         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES,
71                 KEY_TYPE_BOOL);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ENABLE_MMS_READ_REPORTS, KEY_TYPE_BOOL)72         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ENABLE_MMS_READ_REPORTS, KEY_TYPE_BOOL);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ENABLE_MMS_DELIVERY_REPORTS, KEY_TYPE_BOOL)73         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ENABLE_MMS_DELIVERY_REPORTS,
74                 KEY_TYPE_BOOL);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_SUPPORT_HTTP_CHARSET_HEADER, KEY_TYPE_BOOL)75         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_SUPPORT_HTTP_CHARSET_HEADER,
76                 KEY_TYPE_BOOL);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_MAX_MESSAGE_SIZE, KEY_TYPE_INT)77         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_MAX_MESSAGE_SIZE, KEY_TYPE_INT);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_MAX_IMAGE_HEIGHT, KEY_TYPE_INT)78         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_MAX_IMAGE_HEIGHT, KEY_TYPE_INT);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_MAX_IMAGE_WIDTH, KEY_TYPE_INT)79         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_MAX_IMAGE_WIDTH, KEY_TYPE_INT);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_RECIPIENT_LIMIT, KEY_TYPE_INT)80         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_RECIPIENT_LIMIT, KEY_TYPE_INT);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_HTTP_SOCKET_TIMEOUT, KEY_TYPE_INT)81         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_HTTP_SOCKET_TIMEOUT, KEY_TYPE_INT);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ALIAS_MIN_CHARS, KEY_TYPE_INT)82         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ALIAS_MIN_CHARS, KEY_TYPE_INT);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ALIAS_MAX_CHARS, KEY_TYPE_INT)83         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_ALIAS_MAX_CHARS, KEY_TYPE_INT);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_SMS_TO_MMS_TEXT_THRESHOLD, KEY_TYPE_INT)84         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_SMS_TO_MMS_TEXT_THRESHOLD, KEY_TYPE_INT);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD, KEY_TYPE_INT)85         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD,
86                 KEY_TYPE_INT);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_MAX_MESSAGE_TEXT_SIZE, KEY_TYPE_INT)87         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_MAX_MESSAGE_TEXT_SIZE, KEY_TYPE_INT);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_MAX_SUBJECT_LENGTH, KEY_TYPE_INT)88         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_MAX_SUBJECT_LENGTH, KEY_TYPE_INT);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_UA_PROF_TAG_NAME, KEY_TYPE_STRING)89         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_UA_PROF_TAG_NAME, KEY_TYPE_STRING);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_HTTP_PARAMS, KEY_TYPE_STRING)90         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_HTTP_PARAMS, KEY_TYPE_STRING);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_EMAIL_GATEWAY_NUMBER, KEY_TYPE_STRING)91         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_EMAIL_GATEWAY_NUMBER, KEY_TYPE_STRING);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_NAI_SUFFIX, KEY_TYPE_STRING)92         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_NAI_SUFFIX, KEY_TYPE_STRING);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_UA_PROF_URL, KEY_TYPE_STRING)93         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_UA_PROF_URL, KEY_TYPE_STRING);
sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_USER_AGENT, KEY_TYPE_STRING)94         sKeyTypeMap.put(CarrierConfigValuesLoader.CONFIG_USER_AGENT, KEY_TYPE_STRING);
95     }
96 
97     // A map that stores all MmsConfigs, one per active subscription. For pre-LMSim, this will
98     // contain just one entry with the default self sub id; for LMSim and above, this will contain
99     // all active sub ids but the default subscription id - the default subscription id will be
100     // resolved to an active sub id during runtime.
101     private static final Map<Integer, MmsConfig> sSubIdToMmsConfigMap = Maps.newHashMap();
102     // The fallback values
103     private static final MmsConfig sFallback =
104             new MmsConfig(ParticipantData.DEFAULT_SELF_SUB_ID, new Bundle());
105 
106     // Per-subscription configuration values.
107     private final Bundle mValues;
108     private final int mSubId;
109 
110     /**
111      * Retrieves the MmsConfig instance associated with the given {@code subId}
112      */
get(final int subId)113     public static MmsConfig get(final int subId) {
114         final int realSubId = PhoneUtils.getDefault().getEffectiveSubId(subId);
115         synchronized (sSubIdToMmsConfigMap) {
116             final MmsConfig mmsConfig = sSubIdToMmsConfigMap.get(realSubId);
117             if (mmsConfig == null) {
118                 // The subId is no longer valid. Fall back to the default config.
119                 LogUtil.e(LogUtil.BUGLE_TAG, "Get mms config failed: invalid subId. subId=" + subId
120                         + ", real subId=" + realSubId
121                         + ", map=" + sSubIdToMmsConfigMap.keySet());
122                 return sFallback;
123             }
124             return mmsConfig;
125         }
126     }
127 
MmsConfig(final int subId, final Bundle values)128     private MmsConfig(final int subId, final Bundle values) {
129         mSubId = subId;
130         mValues = values;
131     }
132 
133     /**
134      * Same as load() but doing it using an async thread from SafeAsyncTask thread pool.
135      */
loadAsync()136     public static void loadAsync() {
137         SafeAsyncTask.executeOnThreadPool(new Runnable() {
138             @Override
139             public void run() {
140                 load();
141             }
142         });
143     }
144 
145     /**
146      * Reload the device and per-subscription settings.
147      */
load()148     public static synchronized void load() {
149         final BugleCarrierConfigValuesLoader loader = Factory.get().getCarrierConfigValuesLoader();
150         // Rebuild the entire MmsConfig map.
151         sSubIdToMmsConfigMap.clear();
152         loader.reset();
153         if (OsUtil.isAtLeastL_MR1()) {
154             final List<SubscriptionInfo> subInfoRecords =
155                     PhoneUtils.getDefault().toLMr1().getActiveSubscriptionInfoList();
156             if (subInfoRecords == null) {
157                 LogUtil.w(TAG, "Loading mms config failed: no active SIM");
158                 return;
159             }
160             for (SubscriptionInfo subInfoRecord : subInfoRecords) {
161                 final int subId = subInfoRecord.getSubscriptionId();
162                 final Bundle values = loader.get(subId);
163                 addMmsConfig(new MmsConfig(subId, values));
164             }
165         } else {
166             final Bundle values = loader.get(ParticipantData.DEFAULT_SELF_SUB_ID);
167             addMmsConfig(new MmsConfig(ParticipantData.DEFAULT_SELF_SUB_ID, values));
168         }
169     }
170 
addMmsConfig(MmsConfig mmsConfig)171     private static void addMmsConfig(MmsConfig mmsConfig) {
172         Assert.isTrue(OsUtil.isAtLeastL_MR1() !=
173                 (mmsConfig.mSubId == ParticipantData.DEFAULT_SELF_SUB_ID));
174         sSubIdToMmsConfigMap.put(mmsConfig.mSubId, mmsConfig);
175     }
176 
getSmsToMmsTextThreshold()177     public int getSmsToMmsTextThreshold() {
178         return mValues.getInt(CarrierConfigValuesLoader.CONFIG_SMS_TO_MMS_TEXT_THRESHOLD,
179                 CarrierConfigValuesLoader.CONFIG_SMS_TO_MMS_TEXT_THRESHOLD_DEFAULT);
180     }
181 
getSmsToMmsTextLengthThreshold()182     public int getSmsToMmsTextLengthThreshold() {
183         return mValues.getInt(CarrierConfigValuesLoader.CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD,
184                 CarrierConfigValuesLoader.CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD_DEFAULT);
185     }
186 
getMaxMessageSize()187     public int getMaxMessageSize() {
188         return mValues.getInt(CarrierConfigValuesLoader.CONFIG_MAX_MESSAGE_SIZE,
189                 CarrierConfigValuesLoader.CONFIG_MAX_MESSAGE_SIZE_DEFAULT);
190     }
191 
192     /**
193      * Return the largest MaxMessageSize for any subid
194      */
getMaxMaxMessageSize()195     public static int getMaxMaxMessageSize() {
196         int maxMax = 0;
197         for (MmsConfig config : sSubIdToMmsConfigMap.values()) {
198             maxMax = Math.max(maxMax, config.getMaxMessageSize());
199         }
200         return maxMax > 0 ? maxMax : sFallback.getMaxMessageSize();
201     }
202 
getTransIdEnabled()203     public boolean getTransIdEnabled() {
204         return mValues.getBoolean(CarrierConfigValuesLoader.CONFIG_ENABLED_TRANS_ID,
205                 CarrierConfigValuesLoader.CONFIG_ENABLED_TRANS_ID_DEFAULT);
206     }
207 
getEmailGateway()208     public String getEmailGateway() {
209         return mValues.getString(CarrierConfigValuesLoader.CONFIG_EMAIL_GATEWAY_NUMBER,
210                 CarrierConfigValuesLoader.CONFIG_EMAIL_GATEWAY_NUMBER_DEFAULT);
211     }
212 
getMaxImageHeight()213     public int getMaxImageHeight() {
214         return mValues.getInt(CarrierConfigValuesLoader.CONFIG_MAX_IMAGE_HEIGHT,
215                 CarrierConfigValuesLoader.CONFIG_MAX_IMAGE_HEIGHT_DEFAULT);
216     }
217 
getMaxImageWidth()218     public int getMaxImageWidth() {
219         return mValues.getInt(CarrierConfigValuesLoader.CONFIG_MAX_IMAGE_WIDTH,
220                 CarrierConfigValuesLoader.CONFIG_MAX_IMAGE_WIDTH_DEFAULT);
221     }
222 
getRecipientLimit()223     public int getRecipientLimit() {
224         final int limit = mValues.getInt(CarrierConfigValuesLoader.CONFIG_RECIPIENT_LIMIT,
225                 CarrierConfigValuesLoader.CONFIG_RECIPIENT_LIMIT_DEFAULT);
226         return limit < 0 ? Integer.MAX_VALUE : limit;
227     }
228 
getMaxTextLimit()229     public int getMaxTextLimit() {
230         final int max = mValues.getInt(CarrierConfigValuesLoader.CONFIG_MAX_MESSAGE_TEXT_SIZE,
231                 CarrierConfigValuesLoader.CONFIG_MAX_MESSAGE_TEXT_SIZE_DEFAULT);
232         return max > -1 ? max : DEFAULT_MAX_TEXT_LENGTH;
233     }
234 
getMultipartSmsEnabled()235     public boolean getMultipartSmsEnabled() {
236         return mValues.getBoolean(CarrierConfigValuesLoader.CONFIG_ENABLE_MULTIPART_SMS,
237                 CarrierConfigValuesLoader.CONFIG_ENABLE_MULTIPART_SMS_DEFAULT);
238     }
239 
getSendMultipartSmsAsSeparateMessages()240     public boolean getSendMultipartSmsAsSeparateMessages() {
241         return mValues.getBoolean(
242                 CarrierConfigValuesLoader.CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES,
243                 CarrierConfigValuesLoader.CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES_DEFAULT);
244     }
245 
getSMSDeliveryReportsEnabled()246     public boolean getSMSDeliveryReportsEnabled() {
247         return mValues.getBoolean(CarrierConfigValuesLoader.CONFIG_ENABLE_SMS_DELIVERY_REPORTS,
248                 CarrierConfigValuesLoader.CONFIG_ENABLE_SMS_DELIVERY_REPORTS_DEFAULT);
249     }
250 
getNotifyWapMMSC()251     public boolean getNotifyWapMMSC() {
252         return mValues.getBoolean(CarrierConfigValuesLoader.CONFIG_ENABLED_NOTIFY_WAP_MMSC,
253                 CarrierConfigValuesLoader.CONFIG_ENABLED_NOTIFY_WAP_MMSC_DEFAULT);
254     }
255 
isAliasEnabled()256     public boolean isAliasEnabled() {
257         return mValues.getBoolean(CarrierConfigValuesLoader.CONFIG_ALIAS_ENABLED,
258                 CarrierConfigValuesLoader.CONFIG_ALIAS_ENABLED_DEFAULT);
259     }
260 
getAliasMinChars()261     public int getAliasMinChars() {
262         return mValues.getInt(CarrierConfigValuesLoader.CONFIG_ALIAS_MIN_CHARS,
263                 CarrierConfigValuesLoader.CONFIG_ALIAS_MIN_CHARS_DEFAULT);
264     }
265 
getAliasMaxChars()266     public int getAliasMaxChars() {
267         return mValues.getInt(CarrierConfigValuesLoader.CONFIG_ALIAS_MAX_CHARS,
268                 CarrierConfigValuesLoader.CONFIG_ALIAS_MAX_CHARS_DEFAULT);
269     }
270 
getAllowAttachAudio()271     public boolean getAllowAttachAudio() {
272         return mValues.getBoolean(CarrierConfigValuesLoader.CONFIG_ALLOW_ATTACH_AUDIO,
273                 CarrierConfigValuesLoader.CONFIG_ALLOW_ATTACH_AUDIO_DEFAULT);
274     }
275 
getMaxSubjectLength()276     public int getMaxSubjectLength() {
277         return mValues.getInt(CarrierConfigValuesLoader.CONFIG_MAX_SUBJECT_LENGTH,
278                 CarrierConfigValuesLoader.CONFIG_MAX_SUBJECT_LENGTH_DEFAULT);
279     }
280 
getGroupMmsEnabled()281     public boolean getGroupMmsEnabled() {
282         return mValues.getBoolean(CarrierConfigValuesLoader.CONFIG_ENABLE_GROUP_MMS,
283                 CarrierConfigValuesLoader.CONFIG_ENABLE_GROUP_MMS_DEFAULT);
284     }
285 
getSupportMmsContentDisposition()286     public boolean getSupportMmsContentDisposition() {
287         return mValues.getBoolean(CarrierConfigValuesLoader.CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION,
288                 CarrierConfigValuesLoader.CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION_DEFAULT);
289     }
290 
getShowCellBroadcast()291     public boolean getShowCellBroadcast() {
292         return mValues.getBoolean(CarrierConfigValuesLoader.CONFIG_CELL_BROADCAST_APP_LINKS,
293                 CarrierConfigValuesLoader.CONFIG_CELL_BROADCAST_APP_LINKS_DEFAULT);
294     }
295 
getValue(final String key)296     public Object getValue(final String key) {
297         return mValues.get(key);
298     }
299 
keySet()300     public Set<String> keySet() {
301         return mValues.keySet();
302     }
303 
getKeyType(final String key)304     public static String getKeyType(final String key) {
305         return sKeyTypeMap.get(key);
306     }
307 
update(final String type, final String key, final String value)308     public void update(final String type, final String key, final String value) {
309         BugleCarrierConfigValuesLoader.update(mValues, type, key, value);
310     }
311 }
312