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