SmsApplication.java revision 6dc23862ef345df2acd3ab36a432292d264d6a73
1/* 2 * Copyright (C) 2013 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 17package com.android.internal.telephony; 18 19import android.Manifest.permission; 20import android.app.AppOpsManager; 21import android.content.ComponentName; 22import android.content.Context; 23import android.content.Intent; 24import android.content.IntentFilter; 25import android.content.pm.ActivityInfo; 26import android.content.pm.PackageInfo; 27import android.content.pm.PackageManager; 28import android.content.pm.ResolveInfo; 29import android.content.pm.ServiceInfo; 30import android.content.pm.PackageManager.NameNotFoundException; 31import android.content.res.Resources; 32import android.net.Uri; 33import android.provider.Settings; 34import android.provider.Telephony.Sms.Intents; 35import android.telephony.Rlog; 36import android.telephony.SmsManager; 37import android.telephony.TelephonyManager; 38import com.android.internal.content.PackageMonitor; 39 40import java.util.Collection; 41import java.util.HashMap; 42import java.util.List; 43 44/** 45 * Class for managing the primary application that we will deliver SMS/MMS messages to 46 * 47 * {@hide} 48 */ 49public final class SmsApplication { 50 static final String LOG_TAG = "SmsApplication"; 51 private static final String PHONE_PACKAGE_NAME = "com.android.phone"; 52 private static final String BLUETOOTH_PACKAGE_NAME = "com.android.bluetooth"; 53 private static final String MMS_SERVICE_PACKAGE_NAME = "com.android.mms.service"; 54 55 private static final String SCHEME_SMS = "sms"; 56 private static final String SCHEME_SMSTO = "smsto"; 57 private static final String SCHEME_MMS = "mms"; 58 private static final String SCHEME_MMSTO = "mmsto"; 59 60 private static SmsPackageMonitor sSmsPackageMonitor = null; 61 62 public static class SmsApplicationData { 63 /** 64 * Name of this SMS app for display. 65 */ 66 public String mApplicationName; 67 68 /** 69 * Package name for this SMS app. 70 */ 71 public String mPackageName; 72 73 /** 74 * The class name of the SMS_DELIVER_ACTION receiver in this app. 75 */ 76 public String mSmsReceiverClass; 77 78 /** 79 * The class name of the WAP_PUSH_DELIVER_ACTION receiver in this app. 80 */ 81 public String mMmsReceiverClass; 82 83 /** 84 * The class name of the ACTION_RESPOND_VIA_MESSAGE intent in this app. 85 */ 86 public String mRespondViaMessageClass; 87 88 /** 89 * The class name of the ACTION_SENDTO intent in this app. 90 */ 91 public String mSendToClass; 92 93 /** 94 * The user-id for this application 95 */ 96 public int mUid; 97 98 /** 99 * Returns true if this SmsApplicationData is complete (all intents handled). 100 * @return 101 */ 102 public boolean isComplete() { 103 return (mSmsReceiverClass != null && mMmsReceiverClass != null 104 && mRespondViaMessageClass != null && mSendToClass != null); 105 } 106 107 public SmsApplicationData(String applicationName, String packageName, int uid) { 108 mApplicationName = applicationName; 109 mPackageName = packageName; 110 mUid = uid; 111 } 112 } 113 114 /** 115 * Returns the list of available SMS apps defined as apps that are registered for both the 116 * SMS_RECEIVED_ACTION (SMS) and WAP_PUSH_RECEIVED_ACTION (MMS) broadcasts (and their broadcast 117 * receivers are enabled) 118 * 119 * Requirements to be an SMS application: 120 * Implement SMS_DELIVER_ACTION broadcast receiver. 121 * Require BROADCAST_SMS permission. 122 * 123 * Implement WAP_PUSH_DELIVER_ACTION broadcast receiver. 124 * Require BROADCAST_WAP_PUSH permission. 125 * 126 * Implement RESPOND_VIA_MESSAGE intent. 127 * Support smsto Uri scheme. 128 * Require SEND_RESPOND_VIA_MESSAGE permission. 129 * 130 * Implement ACTION_SENDTO intent. 131 * Support smsto Uri scheme. 132 */ 133 public static Collection<SmsApplicationData> getApplicationCollection(Context context) { 134 PackageManager packageManager = context.getPackageManager(); 135 136 // Get the list of apps registered for SMS 137 Intent intent = new Intent(Intents.SMS_DELIVER_ACTION); 138 List<ResolveInfo> smsReceivers = packageManager.queryBroadcastReceivers(intent, 0); 139 140 HashMap<String, SmsApplicationData> receivers = new HashMap<String, SmsApplicationData>(); 141 142 // Add one entry to the map for every sms receiver (ignoring duplicate sms receivers) 143 for (ResolveInfo resolveInfo : smsReceivers) { 144 final ActivityInfo activityInfo = resolveInfo.activityInfo; 145 if (activityInfo == null) { 146 continue; 147 } 148 if (!permission.BROADCAST_SMS.equals(activityInfo.permission)) { 149 continue; 150 } 151 final String packageName = activityInfo.packageName; 152 if (!receivers.containsKey(packageName)) { 153 final String applicationName = resolveInfo.loadLabel(packageManager).toString(); 154 final SmsApplicationData smsApplicationData = new SmsApplicationData( 155 applicationName, packageName, activityInfo.applicationInfo.uid); 156 smsApplicationData.mSmsReceiverClass = activityInfo.name; 157 receivers.put(packageName, smsApplicationData); 158 } 159 } 160 161 // Update any existing entries with mms receiver class 162 intent = new Intent(Intents.WAP_PUSH_DELIVER_ACTION); 163 intent.setDataAndType(null, "application/vnd.wap.mms-message"); 164 List<ResolveInfo> mmsReceivers = packageManager.queryBroadcastReceivers(intent, 0); 165 for (ResolveInfo resolveInfo : mmsReceivers) { 166 final ActivityInfo activityInfo = resolveInfo.activityInfo; 167 if (activityInfo == null) { 168 continue; 169 } 170 if (!permission.BROADCAST_WAP_PUSH.equals(activityInfo.permission)) { 171 continue; 172 } 173 final String packageName = activityInfo.packageName; 174 final SmsApplicationData smsApplicationData = receivers.get(packageName); 175 if (smsApplicationData != null) { 176 smsApplicationData.mMmsReceiverClass = activityInfo.name; 177 } 178 } 179 180 // Update any existing entries with respond via message intent class. 181 intent = new Intent(TelephonyManager.ACTION_RESPOND_VIA_MESSAGE, 182 Uri.fromParts(SCHEME_SMSTO, "", null)); 183 List<ResolveInfo> respondServices = packageManager.queryIntentServices(intent, 0); 184 for (ResolveInfo resolveInfo : respondServices) { 185 final ServiceInfo serviceInfo = resolveInfo.serviceInfo; 186 if (serviceInfo == null) { 187 continue; 188 } 189 if (!permission.SEND_RESPOND_VIA_MESSAGE.equals(serviceInfo.permission)) { 190 continue; 191 } 192 final String packageName = serviceInfo.packageName; 193 final SmsApplicationData smsApplicationData = receivers.get(packageName); 194 if (smsApplicationData != null) { 195 smsApplicationData.mRespondViaMessageClass = serviceInfo.name; 196 } 197 } 198 199 // Update any existing entries with supports send to. 200 intent = new Intent(Intent.ACTION_SENDTO, 201 Uri.fromParts(SCHEME_SMSTO, "", null)); 202 List<ResolveInfo> sendToActivities = packageManager.queryIntentActivities(intent, 0); 203 for (ResolveInfo resolveInfo : sendToActivities) { 204 final ActivityInfo activityInfo = resolveInfo.activityInfo; 205 if (activityInfo == null) { 206 continue; 207 } 208 final String packageName = activityInfo.packageName; 209 final SmsApplicationData smsApplicationData = receivers.get(packageName); 210 if (smsApplicationData != null) { 211 smsApplicationData.mSendToClass = activityInfo.name; 212 } 213 } 214 215 // Remove any entries for which we did not find all required intents. 216 for (ResolveInfo resolveInfo : smsReceivers) { 217 final ActivityInfo activityInfo = resolveInfo.activityInfo; 218 if (activityInfo == null) { 219 continue; 220 } 221 final String packageName = activityInfo.packageName; 222 final SmsApplicationData smsApplicationData = receivers.get(packageName); 223 if (smsApplicationData != null) { 224 if (!smsApplicationData.isComplete()) { 225 receivers.remove(packageName); 226 } 227 } 228 } 229 return receivers.values(); 230 } 231 232 /** 233 * Checks to see if we have a valid installed SMS application for the specified package name 234 * @return Data for the specified package name or null if there isn't one 235 */ 236 private static SmsApplicationData getApplicationForPackage( 237 Collection<SmsApplicationData> applications, String packageName) { 238 if (packageName == null) { 239 return null; 240 } 241 // Is there an entry in the application list for the specified package? 242 for (SmsApplicationData application : applications) { 243 if (application.mPackageName.contentEquals(packageName)) { 244 return application; 245 } 246 } 247 return null; 248 } 249 250 /** 251 * Get the application we will use for delivering SMS/MMS messages. 252 * 253 * We return the preferred sms application with the following order of preference: 254 * (1) User selected SMS app (if selected, and if still valid) 255 * (2) Android Messaging (if installed) 256 * (3) The currently configured highest priority broadcast receiver 257 * (4) Null 258 */ 259 private static SmsApplicationData getApplication(Context context, boolean updateIfNeeded) { 260 TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); 261 if (!tm.isSmsCapable()) { 262 // No phone, no SMS 263 return null; 264 } 265 266 Collection<SmsApplicationData> applications = getApplicationCollection(context); 267 268 // Determine which application receives the broadcast 269 String defaultApplication = Settings.Secure.getString(context.getContentResolver(), 270 Settings.Secure.SMS_DEFAULT_APPLICATION); 271 272 SmsApplicationData applicationData = null; 273 if (defaultApplication != null) { 274 applicationData = getApplicationForPackage(applications, defaultApplication); 275 } 276 // Picking a new SMS app requires AppOps and Settings.Secure permissions, so we only do 277 // this if the caller asked us to. 278 if (updateIfNeeded && applicationData == null) { 279 // Try to find the default SMS package for this device 280 Resources r = context.getResources(); 281 String defaultPackage = 282 r.getString(com.android.internal.R.string.default_sms_application); 283 applicationData = getApplicationForPackage(applications, defaultPackage); 284 285 if (applicationData == null) { 286 // Are there any applications? 287 if (applications.size() != 0) { 288 applicationData = (SmsApplicationData)applications.toArray()[0]; 289 } 290 } 291 292 // If we found a new default app, update the setting 293 if (applicationData != null) { 294 setDefaultApplication(applicationData.mPackageName, context); 295 } 296 } 297 298 // If we found a package, make sure AppOps permissions are set up correctly 299 if (applicationData != null) { 300 AppOpsManager appOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); 301 302 // We can only call checkOp if we are privileged (updateIfNeeded) or if the app we 303 // are checking is for our current uid. Doing this check from the unprivileged current 304 // SMS app allows us to tell the current SMS app that it is not in a good state and 305 // needs to ask to be the current SMS app again to work properly. 306 if (updateIfNeeded || applicationData.mUid == android.os.Process.myUid()) { 307 // Verify that the SMS app has permissions 308 int mode = appOps.checkOp(AppOpsManager.OP_WRITE_SMS, applicationData.mUid, 309 applicationData.mPackageName); 310 if (mode != AppOpsManager.MODE_ALLOWED) { 311 Rlog.e(LOG_TAG, applicationData.mPackageName + " lost OP_WRITE_SMS: " + 312 (updateIfNeeded ? " (fixing)" : " (no permission to fix)")); 313 if (updateIfNeeded) { 314 appOps.setMode(AppOpsManager.OP_WRITE_SMS, applicationData.mUid, 315 applicationData.mPackageName, AppOpsManager.MODE_ALLOWED); 316 } else { 317 // We can not return a package if permissions are not set up correctly 318 applicationData = null; 319 } 320 } 321 } 322 323 // We can only verify the phone and BT app's permissions from a privileged caller 324 if (updateIfNeeded) { 325 // Ensure this component is still configured as the preferred activity. Usually the 326 // current SMS app will already be the preferred activity - but checking whether or 327 // not this is true is just as expensive as reconfiguring the preferred activity so 328 // we just reconfigure every time. 329 PackageManager packageManager = context.getPackageManager(); 330 configurePreferredActivity(packageManager, new ComponentName( 331 applicationData.mPackageName, applicationData.mSendToClass)); 332 333 // Verify that the phone, BT app and MmsService have permissions 334 try { 335 PackageInfo info = packageManager.getPackageInfo(PHONE_PACKAGE_NAME, 0); 336 int mode = appOps.checkOp(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid, 337 PHONE_PACKAGE_NAME); 338 if (mode != AppOpsManager.MODE_ALLOWED) { 339 Rlog.e(LOG_TAG, PHONE_PACKAGE_NAME + " lost OP_WRITE_SMS: (fixing)"); 340 appOps.setMode(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid, 341 PHONE_PACKAGE_NAME, AppOpsManager.MODE_ALLOWED); 342 } 343 } catch (NameNotFoundException e) { 344 // No phone app on this device (unexpected, even for non-phone devices) 345 Rlog.e(LOG_TAG, "Phone package not found: " + PHONE_PACKAGE_NAME); 346 applicationData = null; 347 } 348 349 try { 350 PackageInfo info = packageManager.getPackageInfo(BLUETOOTH_PACKAGE_NAME, 0); 351 int mode = appOps.checkOp(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid, 352 BLUETOOTH_PACKAGE_NAME); 353 if (mode != AppOpsManager.MODE_ALLOWED) { 354 Rlog.e(LOG_TAG, BLUETOOTH_PACKAGE_NAME + " lost OP_WRITE_SMS: (fixing)"); 355 appOps.setMode(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid, 356 BLUETOOTH_PACKAGE_NAME, AppOpsManager.MODE_ALLOWED); 357 } 358 } catch (NameNotFoundException e) { 359 // No BT app on this device 360 Rlog.e(LOG_TAG, "Bluetooth package not found: " + BLUETOOTH_PACKAGE_NAME); 361 } 362 363 try { 364 PackageInfo info = packageManager.getPackageInfo(MMS_SERVICE_PACKAGE_NAME, 0); 365 int mode = appOps.checkOp(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid, 366 MMS_SERVICE_PACKAGE_NAME); 367 if (mode != AppOpsManager.MODE_ALLOWED) { 368 Rlog.e(LOG_TAG, MMS_SERVICE_PACKAGE_NAME + " lost OP_WRITE_SMS: (fixing)"); 369 appOps.setMode(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid, 370 MMS_SERVICE_PACKAGE_NAME, AppOpsManager.MODE_ALLOWED); 371 } 372 } catch (NameNotFoundException e) { 373 // No phone app on this device (unexpected, even for non-phone devices) 374 Rlog.e(LOG_TAG, "MmsService package not found: " + MMS_SERVICE_PACKAGE_NAME); 375 applicationData = null; 376 } 377 378 } 379 } 380 return applicationData; 381 } 382 383 /** 384 * Sets the specified package as the default SMS/MMS application. The caller of this method 385 * needs to have permission to set AppOps and write to secure settings. 386 */ 387 public static void setDefaultApplication(String packageName, Context context) { 388 TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); 389 if (!tm.isSmsCapable()) { 390 // No phone, no SMS 391 return; 392 } 393 394 // Get old package name 395 String oldPackageName = Settings.Secure.getString(context.getContentResolver(), 396 Settings.Secure.SMS_DEFAULT_APPLICATION); 397 398 if (packageName != null && oldPackageName != null && packageName.equals(oldPackageName)) { 399 // No change 400 return; 401 } 402 403 // We only make the change if the new package is valid 404 PackageManager packageManager = context.getPackageManager(); 405 Collection<SmsApplicationData> applications = getApplicationCollection(context); 406 SmsApplicationData applicationData = getApplicationForPackage(applications, packageName); 407 if (applicationData != null) { 408 // Ignore OP_WRITE_SMS for the previously configured default SMS app. 409 AppOpsManager appOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); 410 if (oldPackageName != null) { 411 try { 412 PackageInfo info = packageManager.getPackageInfo(oldPackageName, 413 PackageManager.GET_UNINSTALLED_PACKAGES); 414 appOps.setMode(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid, 415 oldPackageName, AppOpsManager.MODE_IGNORED); 416 } catch (NameNotFoundException e) { 417 Rlog.w(LOG_TAG, "Old SMS package not found: " + oldPackageName); 418 } 419 } 420 421 // Update the secure setting. 422 Settings.Secure.putString(context.getContentResolver(), 423 Settings.Secure.SMS_DEFAULT_APPLICATION, applicationData.mPackageName); 424 425 // Configure this as the preferred activity for SENDTO sms/mms intents 426 configurePreferredActivity(packageManager, new ComponentName( 427 applicationData.mPackageName, applicationData.mSendToClass)); 428 429 // Allow OP_WRITE_SMS for the newly configured default SMS app. 430 appOps.setMode(AppOpsManager.OP_WRITE_SMS, applicationData.mUid, 431 applicationData.mPackageName, AppOpsManager.MODE_ALLOWED); 432 433 // Phone needs to always have this permission to write to the sms database 434 try { 435 PackageInfo info = packageManager.getPackageInfo(PHONE_PACKAGE_NAME, 0); 436 appOps.setMode(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid, 437 PHONE_PACKAGE_NAME, AppOpsManager.MODE_ALLOWED); 438 } catch (NameNotFoundException e) { 439 // No phone app on this device (unexpected, even for non-phone devices) 440 Rlog.e(LOG_TAG, "Phone package not found: " + PHONE_PACKAGE_NAME); 441 } 442 443 // BT needs to always have this permission to write to the sms database 444 try { 445 PackageInfo info = packageManager.getPackageInfo(BLUETOOTH_PACKAGE_NAME, 0); 446 appOps.setMode(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid, 447 BLUETOOTH_PACKAGE_NAME, AppOpsManager.MODE_ALLOWED); 448 } catch (NameNotFoundException e) { 449 // No BT app on this device 450 Rlog.e(LOG_TAG, "Bluetooth package not found: " + BLUETOOTH_PACKAGE_NAME); 451 } 452 453 // MmsService needs to always have this permission to write to the sms database 454 try { 455 PackageInfo info = packageManager.getPackageInfo(MMS_SERVICE_PACKAGE_NAME, 0); 456 appOps.setMode(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid, 457 MMS_SERVICE_PACKAGE_NAME, AppOpsManager.MODE_ALLOWED); 458 } catch (NameNotFoundException e) { 459 // No phone app on this device (unexpected, even for non-phone devices) 460 Rlog.e(LOG_TAG, "MmsService package not found: " + MMS_SERVICE_PACKAGE_NAME); 461 } 462 } 463 } 464 465 /** 466 * Tracks package changes and ensures that the default SMS app is always configured to be the 467 * preferred activity for SENDTO sms/mms intents. 468 */ 469 private static final class SmsPackageMonitor extends PackageMonitor { 470 final Context mContext; 471 472 public SmsPackageMonitor(Context context) { 473 super(); 474 mContext = context; 475 } 476 477 @Override 478 public void onPackageDisappeared(String packageName, int reason) { 479 onPackageChanged(packageName); 480 } 481 482 @Override 483 public void onPackageAppeared(String packageName, int reason) { 484 onPackageChanged(packageName); 485 } 486 487 @Override 488 public void onPackageModified(String packageName) { 489 onPackageChanged(packageName); 490 } 491 492 private void onPackageChanged(String packageName) { 493 PackageManager packageManager = mContext.getPackageManager(); 494 // Ensure this component is still configured as the preferred activity 495 ComponentName componentName = getDefaultSendToApplication(mContext, true); 496 if (componentName != null) { 497 configurePreferredActivity(packageManager, componentName); 498 } 499 } 500 } 501 502 public static void initSmsPackageMonitor(Context context) { 503 sSmsPackageMonitor = new SmsPackageMonitor(context); 504 sSmsPackageMonitor.register(context, context.getMainLooper(), false); 505 } 506 507 private static void configurePreferredActivity(PackageManager packageManager, 508 ComponentName componentName) { 509 // Add the four activity preferences we want to direct to this app. 510 replacePreferredActivity(packageManager, componentName, SCHEME_SMS); 511 replacePreferredActivity(packageManager, componentName, SCHEME_SMSTO); 512 replacePreferredActivity(packageManager, componentName, SCHEME_MMS); 513 replacePreferredActivity(packageManager, componentName, SCHEME_MMSTO); 514 } 515 516 /** 517 * Updates the ACTION_SENDTO activity to the specified component for the specified scheme. 518 */ 519 private static void replacePreferredActivity(PackageManager packageManager, 520 ComponentName componentName, String scheme) { 521 // Build the set of existing activities that handle this scheme 522 Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts(scheme, "", null)); 523 List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities( 524 intent, PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_RESOLVED_FILTER); 525 526 // Build the set of ComponentNames for these activities 527 final int n = resolveInfoList.size(); 528 ComponentName[] set = new ComponentName[n]; 529 for (int i = 0; i < n; i++) { 530 ResolveInfo info = resolveInfoList.get(i); 531 set[i] = new ComponentName(info.activityInfo.packageName, info.activityInfo.name); 532 } 533 534 // Update the preferred SENDTO activity for the specified scheme 535 IntentFilter intentFilter = new IntentFilter(); 536 intentFilter.addAction(Intent.ACTION_SENDTO); 537 intentFilter.addCategory(Intent.CATEGORY_DEFAULT); 538 intentFilter.addDataScheme(scheme); 539 packageManager.replacePreferredActivity(intentFilter, 540 IntentFilter.MATCH_CATEGORY_SCHEME + IntentFilter.MATCH_ADJUSTMENT_NORMAL, 541 set, componentName); 542 } 543 544 /** 545 * Returns SmsApplicationData for this package if this package is capable of being set as the 546 * default SMS application. 547 */ 548 public static SmsApplicationData getSmsApplicationData(String packageName, Context context) { 549 Collection<SmsApplicationData> applications = getApplicationCollection(context); 550 return getApplicationForPackage(applications, packageName); 551 } 552 553 /** 554 * Gets the default SMS application 555 * @param context context from the calling app 556 * @param updateIfNeeded update the default app if there is no valid default app configured. 557 * @return component name of the app and class to deliver SMS messages to 558 */ 559 public static ComponentName getDefaultSmsApplication(Context context, boolean updateIfNeeded) { 560 ComponentName component = null; 561 SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded); 562 if (smsApplicationData != null) { 563 component = new ComponentName(smsApplicationData.mPackageName, 564 smsApplicationData.mSmsReceiverClass); 565 } 566 return component; 567 } 568 569 /** 570 * Gets the default MMS application 571 * @param context context from the calling app 572 * @param updateIfNeeded update the default app if there is no valid default app configured. 573 * @return component name of the app and class to deliver MMS messages to 574 */ 575 public static ComponentName getDefaultMmsApplication(Context context, boolean updateIfNeeded) { 576 ComponentName component = null; 577 SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded); 578 if (smsApplicationData != null) { 579 component = new ComponentName(smsApplicationData.mPackageName, 580 smsApplicationData.mMmsReceiverClass); 581 } 582 return component; 583 } 584 585 /** 586 * Gets the default Respond Via Message application 587 * @param context context from the calling app 588 * @param updateIfNeeded update the default app if there is no valid default app configured. 589 * @return component name of the app and class to direct Respond Via Message intent to 590 */ 591 public static ComponentName getDefaultRespondViaMessageApplication(Context context, 592 boolean updateIfNeeded) { 593 ComponentName component = null; 594 SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded); 595 if (smsApplicationData != null) { 596 component = new ComponentName(smsApplicationData.mPackageName, 597 smsApplicationData.mRespondViaMessageClass); 598 } 599 return component; 600 } 601 602 /** 603 * Gets the default Send To (smsto) application 604 * @param context context from the calling app 605 * @param updateIfNeeded update the default app if there is no valid default app configured. 606 * @return component name of the app and class to direct SEND_TO (smsto) intent to 607 */ 608 public static ComponentName getDefaultSendToApplication(Context context, 609 boolean updateIfNeeded) { 610 ComponentName component = null; 611 SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded); 612 if (smsApplicationData != null) { 613 component = new ComponentName(smsApplicationData.mPackageName, 614 smsApplicationData.mSendToClass); 615 } 616 return component; 617 } 618 619 /** 620 * Returns whether need to write the SMS message to SMS database for this package. 621 */ 622 public static boolean shouldWriteMessageForPackage(String packageName, Context context) { 623 if (packageName == null) return true; 624 625 if (SmsManager.getDefault().getAutoPersisting()) { 626 return true; 627 } 628 629 String defaultSmsPackage = null; 630 ComponentName component = getDefaultSmsApplication(context, false); 631 if (component != null) { 632 defaultSmsPackage = component.getPackageName(); 633 } 634 635 if ((defaultSmsPackage == null || !defaultSmsPackage.equals(packageName)) && 636 !packageName.equals(BLUETOOTH_PACKAGE_NAME)) { 637 // To write the message for someone other than the default SMS and BT app 638 return true; 639 } 640 641 return false; 642 } 643} 644