• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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          */
isComplete()100         public boolean isComplete() {
101             return (mSmsReceiverClass != null && mMmsReceiverClass != null
102                     && mRespondViaMessageClass != null && mSendToClass != null);
103         }
104 
SmsApplicationData(String applicationName, String packageName, int uid)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      */
getApplicationCollection(Context context)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      */
getApplicationForPackage( Collection<SmsApplicationData> applications, String packageName)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      */
getApplication(Context context, boolean updateIfNeeded)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      */
setDefaultApplication(String packageName, Context context)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 
SmsPackageMonitor(Context context)444         public SmsPackageMonitor(Context context) {
445             super();
446             mContext = context;
447         }
448 
449         @Override
onPackageDisappeared(String packageName, int reason)450         public void onPackageDisappeared(String packageName, int reason) {
451             onPackageChanged(packageName);
452         }
453 
454         @Override
onPackageAppeared(String packageName, int reason)455         public void onPackageAppeared(String packageName, int reason) {
456             onPackageChanged(packageName);
457         }
458 
459         @Override
onPackageModified(String packageName)460         public void onPackageModified(String packageName) {
461             onPackageChanged(packageName);
462         }
463 
onPackageChanged(String packageName)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 
initSmsPackageMonitor(Context context)474     public static void initSmsPackageMonitor(Context context) {
475         sSmsPackageMonitor = new SmsPackageMonitor(context);
476         sSmsPackageMonitor.register(context, context.getMainLooper(), false);
477     }
478 
configurePreferredActivity(PackageManager packageManager, ComponentName componentName)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      */
replacePreferredActivity(PackageManager packageManager, ComponentName componentName, String scheme)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      */
getSmsApplicationData(String packageName, Context context)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      */
getDefaultSmsApplication(Context context, boolean updateIfNeeded)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      */
getDefaultMmsApplication(Context context, boolean updateIfNeeded)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      */
getDefaultRespondViaMessageApplication(Context context, boolean updateIfNeeded)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      */
getDefaultSendToApplication(Context context, boolean updateIfNeeded)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      */
shouldWriteMessageForPackage(String packageName, Context context)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