Home | History | Annotate | Download | only in telephony
      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