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