1 /* 2 * Copyright (C) 2009 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; 18 19 import java.io.IOException; 20 21 import org.xmlpull.v1.XmlPullParser; 22 import org.xmlpull.v1.XmlPullParserException; 23 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.SharedPreferences; 27 import android.content.res.XmlResourceParser; 28 import android.preference.PreferenceManager; 29 import android.provider.Telephony; 30 import android.text.TextUtils; 31 import android.util.Log; 32 33 import com.android.internal.telephony.TelephonyProperties; 34 import com.android.mms.ui.MessageUtils; 35 import com.android.mms.ui.MessagingPreferenceActivity; 36 37 public class MmsConfig { 38 private static final String TAG = "MmsConfig"; 39 private static final boolean DEBUG = true; 40 private static final boolean LOCAL_LOGV = false; 41 42 private static final String DEFAULT_HTTP_KEY_X_WAP_PROFILE = "x-wap-profile"; 43 private static final String DEFAULT_USER_AGENT = "Android-Mms/2.0"; 44 45 private static final String MMS_APP_PACKAGE = "com.android.mms"; 46 47 private static final String SMS_PROMO_DISMISSED_KEY = "sms_promo_dismissed_key"; 48 49 private static final int MAX_IMAGE_HEIGHT = 480; 50 private static final int MAX_IMAGE_WIDTH = 640; 51 private static final int MAX_TEXT_LENGTH = 2000; 52 53 /** 54 * Whether to hide MMS functionality from the user (i.e. SMS only). 55 */ 56 private static boolean mTransIdEnabled = false; 57 private static int mMmsEnabled = 1; // default to true 58 private static int mMaxMessageSize = 300 * 1024; // default to 300k max size 59 private static String mUserAgent = DEFAULT_USER_AGENT; 60 private static String mUaProfTagName = DEFAULT_HTTP_KEY_X_WAP_PROFILE; 61 private static String mUaProfUrl = null; 62 private static String mHttpParams = null; 63 private static String mHttpParamsLine1Key = null; 64 private static String mEmailGateway = null; 65 private static int mMaxImageHeight = MAX_IMAGE_HEIGHT; // default value 66 private static int mMaxImageWidth = MAX_IMAGE_WIDTH; // default value 67 private static int mRecipientLimit = Integer.MAX_VALUE; // default value 68 private static int mDefaultSMSMessagesPerThread = 10000; // default value 69 private static int mDefaultMMSMessagesPerThread = 1000; // default value 70 private static int mMinMessageCountPerThread = 2; // default value 71 private static int mMaxMessageCountPerThread = 5000; // default value 72 private static int mHttpSocketTimeout = 60*1000; // default to 1 min 73 private static int mMinimumSlideElementDuration = 7; // default to 7 sec 74 private static boolean mNotifyWapMMSC = false; 75 private static boolean mAllowAttachAudio = true; 76 77 // If mEnableMultipartSMS is true, long sms messages are always sent as multi-part sms 78 // messages, with no checked limit on the number of segments. 79 // If mEnableMultipartSMS is false, then as soon as the user types a message longer 80 // than a single segment (i.e. 140 chars), then the message will turn into and be sent 81 // as an mms message. This feature exists for carriers that don't support multi-part sms's. 82 private static boolean mEnableMultipartSMS = true; 83 84 // If mEnableMultipartSMS is true and mSmsToMmsTextThreshold > 1, then multi-part SMS messages 85 // will be converted into a single mms message. For example, if the mms_config.xml file 86 // specifies <int name="smsToMmsTextThreshold">4</int>, then on the 5th sms segment, the 87 // message will be converted to an mms. 88 private static int mSmsToMmsTextThreshold = -1; 89 90 private static boolean mEnableSlideDuration = true; 91 private static boolean mEnableMMSReadReports = true; // key: "enableMMSReadReports" 92 private static boolean mEnableSMSDeliveryReports = true; // key: "enableSMSDeliveryReports" 93 private static boolean mEnableMMSDeliveryReports = true; // key: "enableMMSDeliveryReports" 94 private static int mMaxTextLength = -1; 95 96 // This is the max amount of storage multiplied by mMaxMessageSize that we 97 // allow of unsent messages before blocking the user from sending any more 98 // MMS's. 99 private static int mMaxSizeScaleForPendingMmsAllowed = 4; // default value 100 101 // Email gateway alias support, including the master switch and different rules 102 private static boolean mAliasEnabled = false; 103 private static int mAliasRuleMinChars = 2; 104 private static int mAliasRuleMaxChars = 48; 105 106 private static int mMaxSubjectLength = 40; // maximum number of characters allowed for mms 107 // subject 108 109 // If mEnableGroupMms is true, a message with multiple recipients, regardless of contents, 110 // will be sent as a single MMS message with multiple "TO" fields set for each recipient. 111 // If mEnableGroupMms is false, the group MMS setting/preference will be hidden in the settings 112 // activity. 113 private static boolean mEnableGroupMms = true; 114 115 public static void init(Context context) { 116 if (LOCAL_LOGV) { 117 Log.v(TAG, "MmsConfig.init()"); 118 } 119 // Always put the mnc/mcc in the log so we can tell which mms_config.xml was loaded. 120 Log.v(TAG, "mnc/mcc: " + 121 android.os.SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC)); 122 123 loadMmsSettings(context); 124 } 125 126 public static boolean isSmsEnabled(Context context) { 127 String defaultSmsApplication = Telephony.Sms.getDefaultSmsPackage(context); 128 129 if (defaultSmsApplication != null && defaultSmsApplication.equals(MMS_APP_PACKAGE)) { 130 return true; 131 } 132 return false; 133 } 134 135 public static boolean isSmsPromoDismissed(Context context) { 136 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); 137 return preferences.getBoolean(SMS_PROMO_DISMISSED_KEY, false); 138 } 139 140 public static void setSmsPromoDismissed(Context context) { 141 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); 142 SharedPreferences.Editor editor = preferences.edit(); 143 editor.putBoolean(SMS_PROMO_DISMISSED_KEY, true); 144 editor.apply(); 145 } 146 147 public static Intent getRequestDefaultSmsAppActivity() { 148 final Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT); 149 intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, MMS_APP_PACKAGE); 150 return intent; 151 } 152 153 public static int getSmsToMmsTextThreshold() { 154 return mSmsToMmsTextThreshold; 155 } 156 157 public static boolean getMmsEnabled() { 158 return mMmsEnabled == 1 ? true : false; 159 } 160 161 public static int getMaxMessageSize() { 162 if (LOCAL_LOGV) { 163 Log.v(TAG, "MmsConfig.getMaxMessageSize(): " + mMaxMessageSize); 164 } 165 return mMaxMessageSize; 166 } 167 168 /** 169 * This function returns the value of "enabledTransID" present in mms_config file. 170 * In case of single segment wap push message, this "enabledTransID" indicates whether 171 * TransactionID should be appended to URI or not. 172 */ 173 public static boolean getTransIdEnabled() { 174 return mTransIdEnabled; 175 } 176 177 public static String getUserAgent() { 178 return mUserAgent; 179 } 180 181 public static String getUaProfTagName() { 182 return mUaProfTagName; 183 } 184 185 public static String getUaProfUrl() { 186 return mUaProfUrl; 187 } 188 189 public static String getHttpParams() { 190 return mHttpParams; 191 } 192 193 public static String getHttpParamsLine1Key() { 194 return mHttpParamsLine1Key; 195 } 196 197 public static String getEmailGateway() { 198 return mEmailGateway; 199 } 200 201 public static int getMaxImageHeight() { 202 return mMaxImageHeight; 203 } 204 205 public static int getMaxImageWidth() { 206 return mMaxImageWidth; 207 } 208 209 public static int getRecipientLimit() { 210 return mRecipientLimit; 211 } 212 213 public static int getMaxTextLimit() { 214 return mMaxTextLength > -1 ? mMaxTextLength : MAX_TEXT_LENGTH; 215 } 216 217 public static int getDefaultSMSMessagesPerThread() { 218 return mDefaultSMSMessagesPerThread; 219 } 220 221 public static int getDefaultMMSMessagesPerThread() { 222 return mDefaultMMSMessagesPerThread; 223 } 224 225 public static int getMinMessageCountPerThread() { 226 return mMinMessageCountPerThread; 227 } 228 229 public static int getMaxMessageCountPerThread() { 230 return mMaxMessageCountPerThread; 231 } 232 233 public static int getHttpSocketTimeout() { 234 return mHttpSocketTimeout; 235 } 236 237 public static int getMinimumSlideElementDuration() { 238 return mMinimumSlideElementDuration; 239 } 240 241 public static boolean getMultipartSmsEnabled() { 242 return mEnableMultipartSMS; 243 } 244 245 public static boolean getSlideDurationEnabled() { 246 return mEnableSlideDuration; 247 } 248 249 public static boolean getMMSReadReportsEnabled() { 250 return mEnableMMSReadReports; 251 } 252 253 public static boolean getSMSDeliveryReportsEnabled() { 254 return mEnableSMSDeliveryReports; 255 } 256 257 public static boolean getMMSDeliveryReportsEnabled() { 258 return mEnableMMSDeliveryReports; 259 } 260 261 public static boolean getNotifyWapMMSC() { 262 return mNotifyWapMMSC; 263 } 264 265 public static int getMaxSizeScaleForPendingMmsAllowed() { 266 return mMaxSizeScaleForPendingMmsAllowed; 267 } 268 269 public static boolean isAliasEnabled() { 270 return mAliasEnabled; 271 } 272 273 public static int getAliasMinChars() { 274 return mAliasRuleMinChars; 275 } 276 277 public static int getAliasMaxChars() { 278 return mAliasRuleMaxChars; 279 } 280 281 public static boolean getAllowAttachAudio() { 282 return mAllowAttachAudio; 283 } 284 285 public static int getMaxSubjectLength() { 286 return mMaxSubjectLength; 287 } 288 289 public static boolean getGroupMmsEnabled() { 290 return mEnableGroupMms; 291 } 292 293 public static final void beginDocument(XmlPullParser parser, String firstElementName) throws XmlPullParserException, IOException 294 { 295 int type; 296 while ((type=parser.next()) != parser.START_TAG 297 && type != parser.END_DOCUMENT) { 298 ; 299 } 300 301 if (type != parser.START_TAG) { 302 throw new XmlPullParserException("No start tag found"); 303 } 304 305 if (!parser.getName().equals(firstElementName)) { 306 throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() + 307 ", expected " + firstElementName); 308 } 309 } 310 311 public static final void nextElement(XmlPullParser parser) throws XmlPullParserException, IOException 312 { 313 int type; 314 while ((type=parser.next()) != parser.START_TAG 315 && type != parser.END_DOCUMENT) { 316 ; 317 } 318 } 319 320 private static void loadMmsSettings(Context context) { 321 XmlResourceParser parser = context.getResources().getXml(R.xml.mms_config); 322 323 try { 324 beginDocument(parser, "mms_config"); 325 326 while (true) { 327 nextElement(parser); 328 String tag = parser.getName(); 329 if (tag == null) { 330 break; 331 } 332 String name = parser.getAttributeName(0); 333 String value = parser.getAttributeValue(0); 334 String text = null; 335 if (parser.next() == XmlPullParser.TEXT) { 336 text = parser.getText(); 337 } 338 339 if (DEBUG) { 340 Log.v(TAG, "tag: " + tag + " value: " + value + " - " + 341 text); 342 } 343 if ("name".equalsIgnoreCase(name)) { 344 if ("bool".equals(tag)) { 345 // bool config tags go here 346 if ("enabledMMS".equalsIgnoreCase(value)) { 347 mMmsEnabled = "true".equalsIgnoreCase(text) ? 1 : 0; 348 } else if ("enabledTransID".equalsIgnoreCase(value)) { 349 mTransIdEnabled = "true".equalsIgnoreCase(text); 350 } else if ("enabledNotifyWapMMSC".equalsIgnoreCase(value)) { 351 mNotifyWapMMSC = "true".equalsIgnoreCase(text); 352 } else if ("aliasEnabled".equalsIgnoreCase(value)) { 353 mAliasEnabled = "true".equalsIgnoreCase(text); 354 } else if ("allowAttachAudio".equalsIgnoreCase(value)) { 355 mAllowAttachAudio = "true".equalsIgnoreCase(text); 356 } else if ("enableMultipartSMS".equalsIgnoreCase(value)) { 357 mEnableMultipartSMS = "true".equalsIgnoreCase(text); 358 } else if ("enableSlideDuration".equalsIgnoreCase(value)) { 359 mEnableSlideDuration = "true".equalsIgnoreCase(text); 360 } else if ("enableMMSReadReports".equalsIgnoreCase(value)) { 361 mEnableMMSReadReports = "true".equalsIgnoreCase(text); 362 } else if ("enableSMSDeliveryReports".equalsIgnoreCase(value)) { 363 mEnableSMSDeliveryReports = "true".equalsIgnoreCase(text); 364 } else if ("enableMMSDeliveryReports".equalsIgnoreCase(value)) { 365 mEnableMMSDeliveryReports = "true".equalsIgnoreCase(text); 366 } else if ("enableGroupMms".equalsIgnoreCase(value)) { 367 mEnableGroupMms = "true".equalsIgnoreCase(text); 368 } 369 } else if ("int".equals(tag)) { 370 // int config tags go here 371 if ("maxMessageSize".equalsIgnoreCase(value)) { 372 mMaxMessageSize = Integer.parseInt(text); 373 } else if ("maxImageHeight".equalsIgnoreCase(value)) { 374 mMaxImageHeight = Integer.parseInt(text); 375 } else if ("maxImageWidth".equalsIgnoreCase(value)) { 376 mMaxImageWidth = Integer.parseInt(text); 377 } else if ("defaultSMSMessagesPerThread".equalsIgnoreCase(value)) { 378 mDefaultSMSMessagesPerThread = Integer.parseInt(text); 379 } else if ("defaultMMSMessagesPerThread".equalsIgnoreCase(value)) { 380 mDefaultMMSMessagesPerThread = Integer.parseInt(text); 381 } else if ("minMessageCountPerThread".equalsIgnoreCase(value)) { 382 mMinMessageCountPerThread = Integer.parseInt(text); 383 } else if ("maxMessageCountPerThread".equalsIgnoreCase(value)) { 384 mMaxMessageCountPerThread = Integer.parseInt(text); 385 } else if ("recipientLimit".equalsIgnoreCase(value)) { 386 mRecipientLimit = Integer.parseInt(text); 387 if (mRecipientLimit < 0) { 388 mRecipientLimit = Integer.MAX_VALUE; 389 } 390 } else if ("httpSocketTimeout".equalsIgnoreCase(value)) { 391 mHttpSocketTimeout = Integer.parseInt(text); 392 } else if ("minimumSlideElementDuration".equalsIgnoreCase(value)) { 393 mMinimumSlideElementDuration = Integer.parseInt(text); 394 } else if ("maxSizeScaleForPendingMmsAllowed".equalsIgnoreCase(value)) { 395 mMaxSizeScaleForPendingMmsAllowed = Integer.parseInt(text); 396 } else if ("aliasMinChars".equalsIgnoreCase(value)) { 397 mAliasRuleMinChars = Integer.parseInt(text); 398 } else if ("aliasMaxChars".equalsIgnoreCase(value)) { 399 mAliasRuleMaxChars = Integer.parseInt(text); 400 } else if ("smsToMmsTextThreshold".equalsIgnoreCase(value)) { 401 mSmsToMmsTextThreshold = Integer.parseInt(text); 402 } else if ("maxMessageTextSize".equalsIgnoreCase(value)) { 403 mMaxTextLength = Integer.parseInt(text); 404 } else if ("maxSubjectLength".equalsIgnoreCase(value)) { 405 mMaxSubjectLength = Integer.parseInt(text); 406 } 407 } else if ("string".equals(tag)) { 408 // string config tags go here 409 if ("userAgent".equalsIgnoreCase(value)) { 410 mUserAgent = text; 411 } else if ("uaProfTagName".equalsIgnoreCase(value)) { 412 mUaProfTagName = text; 413 } else if ("uaProfUrl".equalsIgnoreCase(value)) { 414 mUaProfUrl = text; 415 } else if ("httpParams".equalsIgnoreCase(value)) { 416 mHttpParams = text; 417 } else if ("httpParamsLine1Key".equalsIgnoreCase(value)) { 418 mHttpParamsLine1Key = text; 419 } else if ("emailGatewayNumber".equalsIgnoreCase(value)) { 420 mEmailGateway = text; 421 } 422 } 423 } 424 } 425 } catch (XmlPullParserException e) { 426 Log.e(TAG, "loadMmsSettings caught ", e); 427 } catch (NumberFormatException e) { 428 Log.e(TAG, "loadMmsSettings caught ", e); 429 } catch (IOException e) { 430 Log.e(TAG, "loadMmsSettings caught ", e); 431 } finally { 432 parser.close(); 433 } 434 435 String errorStr = null; 436 437 if (getMmsEnabled() && mUaProfUrl == null) { 438 errorStr = "uaProfUrl"; 439 } 440 441 if (errorStr != null) { 442 String err = 443 String.format("MmsConfig.loadMmsSettings mms_config.xml missing %s setting", 444 errorStr); 445 Log.e(TAG, err); 446 } 447 } 448 449 } 450