Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bb506aa0 authored by David Braun's avatar David Braun Committed by Android Git Automerger
Browse files

am 4f7d3a53: Merge "Update preferred activity for SMS related SENDTO intents" into klp-dev

* commit '4f7d3a53':
  Update preferred activity for SMS related SENDTO intents
parents d4ae7c9a 4f7d3a53
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -147,6 +147,9 @@ public class PhoneFactory {
                }
                Rlog.i(LOG_TAG, "defaultSmsApplication: " + packageName);

                // Set up monitor to watch for changes to SMS packages
                SmsApplication.initSmsPackageMonitor(context);

                sMadeDefaults = true;
            }
        }
+99 −3
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.app.AppOpsManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -33,6 +34,7 @@ import android.provider.Settings;
import android.provider.Telephony.Sms.Intents;
import android.telephony.Rlog;
import android.telephony.TelephonyManager;
import com.android.internal.content.PackageMonitor;

import java.util.Collection;
import java.util.HashMap;
@@ -48,6 +50,13 @@ public final class SmsApplication {
    private static final String PHONE_PACKAGE_NAME = "com.android.phone";
    private static final String BLUETOOTH_PACKAGE_NAME = "com.android.bluetooth";

    private static final String SCHEME_SMS = "sms";
    private static final String SCHEME_SMSTO = "smsto";
    private static final String SCHEME_MMS = "mms";
    private static final String SCHEME_MMSTO = "mmsto";

    private static SmsPackageMonitor sSmsPackageMonitor = null;

    public static class SmsApplicationData {
        /**
         * Name of this SMS app for display.
@@ -168,7 +177,7 @@ public final class SmsApplication {

        // Update any existing entries with respond via message intent class.
        intent = new Intent(TelephonyManager.ACTION_RESPOND_VIA_MESSAGE,
                Uri.fromParts("smsto", "", null));
                Uri.fromParts(SCHEME_SMSTO, "", null));
        List<ResolveInfo> respondServices = packageManager.queryIntentServices(intent, 0);
        for (ResolveInfo resolveInfo : respondServices) {
            final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
@@ -187,7 +196,7 @@ public final class SmsApplication {

        // Update any existing entries with supports send to.
        intent = new Intent(Intent.ACTION_SENDTO,
                Uri.fromParts("smsto", "", null));
                Uri.fromParts(SCHEME_SMSTO, "", null));
        List<ResolveInfo> sendToActivities = packageManager.queryIntentActivities(intent, 0);
        for (ResolveInfo resolveInfo : sendToActivities) {
            final ActivityInfo activityInfo = resolveInfo.activityInfo;
@@ -311,8 +320,15 @@ public final class SmsApplication {

            // We can only verify the phone and BT app's permissions from a privileged caller
            if (updateIfNeeded) {
                // Verify that the phone and BT app has permissions
                // Ensure this component is still configured as the preferred activity. Usually the
                // current SMS app will already be the preferred activity - but checking whether or
                // not this is true is just as expensive as reconfiguring the preferred activity so
                // we just reconfigure every time.
                PackageManager packageManager = context.getPackageManager();
                configurePreferredActivity(packageManager, new ComponentName(
                        applicationData.mPackageName, applicationData.mSendToClass));

                // Verify that the phone and BT app has permissions
                try {
                    PackageInfo info = packageManager.getPackageInfo(PHONE_PACKAGE_NAME, 0);
                    int mode = appOps.checkOp(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid,
@@ -388,6 +404,10 @@ public final class SmsApplication {
            Settings.Secure.putString(context.getContentResolver(),
                    Settings.Secure.SMS_DEFAULT_APPLICATION, applicationData.mPackageName);

            // Configure this as the preferred activity for SENDTO sms/mms intents
            configurePreferredActivity(packageManager, new ComponentName(
                    applicationData.mPackageName, applicationData.mSendToClass));

            // Allow OP_WRITE_SMS for the newly configured default SMS app.
            appOps.setMode(AppOpsManager.OP_WRITE_SMS, applicationData.mUid,
                    applicationData.mPackageName, AppOpsManager.MODE_ALLOWED);
@@ -414,6 +434,82 @@ public final class SmsApplication {
        }
    }

    /**
     * Tracks package changes and ensures that the default SMS app is always configured to be the
     * preferred activity for SENDTO sms/mms intents.
     */
    private static final class SmsPackageMonitor extends PackageMonitor {
        final Context mContext;

        public SmsPackageMonitor(Context context) {
            super();
            mContext = context;
        }

        @Override
        public void onPackageDisappeared(String packageName, int reason) {
            onPackageChanged(packageName);
        }

        @Override
        public void onPackageAppeared(String packageName, int reason) {
            onPackageChanged(packageName);
        }

        @Override
        public void onPackageModified(String packageName) {
            onPackageChanged(packageName);
        }

        private void onPackageChanged(String packageName) {
            PackageManager packageManager = mContext.getPackageManager();
            // Ensure this component is still configured as the preferred activity
            ComponentName componentName = getDefaultSendToApplication(mContext, true);
            configurePreferredActivity(packageManager, componentName);
        }
    }

    public static void initSmsPackageMonitor(Context context) {
        sSmsPackageMonitor = new SmsPackageMonitor(context);
        sSmsPackageMonitor.register(context, context.getMainLooper(), false);
    }

    private static void configurePreferredActivity(PackageManager packageManager,
            ComponentName componentName) {
        // Add the four activity preferences we want to direct to this app.
        replacePreferredActivity(packageManager, componentName, SCHEME_SMS);
        replacePreferredActivity(packageManager, componentName, SCHEME_SMSTO);
        replacePreferredActivity(packageManager, componentName, SCHEME_MMS);
        replacePreferredActivity(packageManager, componentName, SCHEME_MMSTO);}

    /**
     * Updates the ACTION_SENDTO activity to the specified component for the specified scheme.
     */
    private static void replacePreferredActivity(PackageManager packageManager,
            ComponentName componentName, String scheme) {
        // Build the set of existing activities that handle this scheme
        Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts(scheme, "", null));
        List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(
                intent, PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_RESOLVED_FILTER);

        // Build the set of ComponentNames for these activities
        final int n = resolveInfoList.size();
        ComponentName[] set = new ComponentName[n];
        for (int i = 0; i < n; i++) {
            ResolveInfo info = resolveInfoList.get(i);
            set[i] = new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
        }

        // Update the preferred SENDTO activity for the specified scheme
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_SENDTO);
        intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
        intentFilter.addDataScheme(scheme);
        packageManager.replacePreferredActivity(intentFilter,
                IntentFilter.MATCH_CATEGORY_SCHEME + IntentFilter.MATCH_ADJUSTMENT_NORMAL,
                set, componentName);
    }

    /**
     * Returns SmsApplicationData for this package if this package is capable of being set as the
     * default SMS application.