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