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