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

Commit 48e1f50b authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Move ServiceListing to SettingsLib"

parents 27e7280b 09d2d717
Loading
Loading
Loading
Loading
+10 −14
Original line number Diff line number Diff line
@@ -27,20 +27,16 @@ import com.android.settings.utils.ManagedServiceSettings;

public class VrListenerSettings extends ManagedServiceSettings {
    private static final String TAG = VrListenerSettings.class.getSimpleName();
    private static final Config CONFIG = getVrListenerConfig();

    private static final Config getVrListenerConfig() {
        final Config c = new Config();
        c.tag = TAG;
        c.setting = Settings.Secure.ENABLED_VR_LISTENERS;
        c.intentAction = VrListenerService.SERVICE_INTERFACE;
        c.permission = android.Manifest.permission.BIND_VR_LISTENER_SERVICE;
        c.noun = "vr listener";
        c.warningDialogTitle = R.string.vr_listener_security_warning_title;
        c.warningDialogSummary = R.string.vr_listener_security_warning_summary;
        c.emptyText = R.string.no_vr_listeners;
        return c;
    }
    private static final Config CONFIG = new Config.Builder()
            .setTag(TAG)
            .setSetting(Settings.Secure.ENABLED_VR_LISTENERS)
            .setIntentAction(VrListenerService.SERVICE_INTERFACE)
            .setPermission(android.Manifest.permission.BIND_VR_LISTENER_SERVICE)
            .setNoun("vr listener")
            .setWarningDialogTitle(R.string.vr_listener_security_warning_title)
            .setWarningDialogSummary(R.string.vr_listener_security_warning_summary)
            .setEmptyText(R.string.no_vr_listeners)
            .build();

    @Override
    protected Config getConfig() {
+30 −31
Original line number Diff line number Diff line
@@ -19,8 +19,9 @@ package com.android.settings.notification;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.Fragment;
import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings;
@@ -33,28 +34,35 @@ import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.utils.ManagedServiceSettings;

/**
 * Settings screen for managing notification listener permissions
 */
public class NotificationAccessSettings extends ManagedServiceSettings {
    private static final String TAG = NotificationAccessSettings.class.getSimpleName();
    private static final Config CONFIG = getNotificationListenerConfig();

    private static Config getNotificationListenerConfig() {
        final Config c = new Config();
        c.tag = TAG;
        c.setting = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
        c.intentAction = NotificationListenerService.SERVICE_INTERFACE;
        c.permission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
        c.noun = "notification listener";
        c.warningDialogTitle = R.string.notification_listener_security_warning_title;
        c.warningDialogSummary = R.string.notification_listener_security_warning_summary;
        c.emptyText = R.string.no_notification_listeners;
        return c;
    }
    private static final Config CONFIG =  new Config.Builder()
            .setTag(TAG)
            .setSetting(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS)
            .setIntentAction(NotificationListenerService.SERVICE_INTERFACE)
            .setPermission(android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE)
            .setNoun("notification listener")
            .setWarningDialogTitle(R.string.notification_listener_security_warning_title)
            .setWarningDialogSummary(R.string.notification_listener_security_warning_summary)
            .setEmptyText(R.string.no_notification_listeners)
            .build();

    private NotificationManager mNm;

    @Override
    public int getMetricsCategory() {
        return MetricsEvent.NOTIFICATION_ACCESS;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mNm = context.getSystemService(NotificationManager.class);
    }

    @Override
    protected Config getConfig() {
        return CONFIG;
@@ -109,14 +117,11 @@ public class NotificationAccessSettings extends ManagedServiceSettings {

    private static void disable(final NotificationAccessSettings parent, final ComponentName cn) {
        parent.mNm.setNotificationListenerAccessGranted(cn, false);
        AsyncTask.execute(new Runnable() {
            @Override
            public void run() {
        AsyncTask.execute(() -> {
            if (!parent.mNm.isNotificationPolicyAccessGrantedForPackage(
                    cn.getPackageName())) {
                parent.mNm.removeAutomaticZenRules(cn.getPackageName());
            }
            }
        });
    }

@@ -153,16 +158,10 @@ public class NotificationAccessSettings extends ManagedServiceSettings {
                    .setMessage(summary)
                    .setCancelable(true)
                    .setPositiveButton(R.string.notification_listener_disable_warning_confirm,
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int id) {
                                    disable(parent, cn);
                                }
                            })
                            (dialog, id) -> disable(parent, cn))
                    .setNegativeButton(R.string.notification_listener_disable_warning_cancel,
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int id) {
                            (dialog, id) -> {
                                // pass
                                }
                            })
                    .create();
        }
+6 −6
Original line number Diff line number Diff line
@@ -64,12 +64,12 @@ public class ZenModeAutomationSettings extends ZenModeSettingsBase {
    }

    protected static ManagedServiceSettings.Config getConditionProviderConfig() {
        final ManagedServiceSettings.Config c = new ManagedServiceSettings.Config();
        c.tag = TAG;
        c.intentAction = ConditionProviderService.SERVICE_INTERFACE;
        c.permission = android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE;
        c.noun = "condition provider";
        return c;
        return new ManagedServiceSettings.Config.Builder()
                .setTag(TAG)
                .setIntentAction(ConditionProviderService.SERVICE_INTERFACE)
                .setPermission(android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE)
                .setNoun("condition provider")
                .build();
    }

    /**
+96 −41
Original line number Diff line number Diff line
@@ -21,11 +21,9 @@ import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.Fragment;
import android.app.NotificationManager;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
@@ -33,8 +31,6 @@ import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
import android.support.v7.preference.PreferenceScreen;
import android.util.IconDrawableFactory;
import android.util.Log;
@@ -46,8 +42,8 @@ import com.android.settings.Utils;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.notification.EmptyTextSettings;
import com.android.settings.widget.AppSwitchPreference;
import com.android.settingslib.applications.ServiceListing;

import java.util.Collections;
import java.util.List;

public abstract class ManagedServiceSettings extends EmptyTextSettings {
@@ -57,8 +53,7 @@ public abstract class ManagedServiceSettings extends EmptyTextSettings {
    protected Context mContext;
    private PackageManager mPm;
    private DevicePolicyManager mDpm;
    protected ServiceListing mServiceListing;
    protected NotificationManager mNm;
    private ServiceListing mServiceListing;
    private IconDrawableFactory mIconDrawableFactory;

    abstract protected Config getConfig();
@@ -74,15 +69,15 @@ public abstract class ManagedServiceSettings extends EmptyTextSettings {
        mContext = getActivity();
        mPm = mContext.getPackageManager();
        mDpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
        mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
        mIconDrawableFactory = IconDrawableFactory.newInstance(mContext);
        mServiceListing = new ServiceListing(mContext, mConfig);
        mServiceListing.addCallback(new ServiceListing.Callback() {
            @Override
            public void onServicesReloaded(List<ServiceInfo> services) {
                updateList(services);
            }
        });
        mServiceListing = new ServiceListing.Builder(mContext)
                .setPermission(mConfig.permission)
                .setIntentAction(mConfig.intentAction)
                .setNoun(mConfig.noun)
                .setSetting(mConfig.setting)
                .setTag(mConfig.tag)
                .build();
        mServiceListing.addCallback(this::updateList);
        setPreferenceScreen(getPreferenceManager().createPreferenceScreen(mContext));
    }

@@ -115,7 +110,7 @@ public abstract class ManagedServiceSettings extends EmptyTextSettings {

        final PreferenceScreen screen = getPreferenceScreen();
        screen.removeAll();
        Collections.sort(services, new PackageItemInfo.DisplayNameComparator(mPm));
        services.sort(new PackageItemInfo.DisplayNameComparator(mPm));
        for (ServiceInfo service : services) {
            final ComponentName cn = new ComponentName(service.packageName, service.name);
            CharSequence title = null;
@@ -144,12 +139,9 @@ public abstract class ManagedServiceSettings extends EmptyTextSettings {
                            service.packageName, managedProfileId)) {
                pref.setSummary(R.string.work_profile_notification_access_blocked_summary);
            }
            pref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
                @Override
                public boolean onPreferenceChange(Preference preference, Object newValue) {
            pref.setOnPreferenceChangeListener((preference, newValue) -> {
                final boolean enable = (boolean) newValue;
                return setEnabled(cn, summary, enable);
                }
            });
            screen.addPreference(pref);
        }
@@ -188,8 +180,8 @@ public abstract class ManagedServiceSettings extends EmptyTextSettings {
    }

    public static class ScaryWarningDialogFragment extends InstrumentedDialogFragment {
        static final String KEY_COMPONENT = "c";
        static final String KEY_LABEL = "l";
        private static final String KEY_COMPONENT = "c";
        private static final String KEY_LABEL = "l";

        @Override
        public int getMetricsCategory() {
@@ -222,29 +214,92 @@ public abstract class ManagedServiceSettings extends EmptyTextSettings {
                    .setTitle(title)
                    .setCancelable(true)
                    .setPositiveButton(R.string.allow,
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int id) {
                                    parent.enable(cn);
                                }
                            })
                            (dialog, id) -> parent.enable(cn))
                    .setNegativeButton(R.string.deny,
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int id) {
                            (dialog, id) -> {
                                // pass
                                }
                            })
                    .create();
        }
    }

    public static class Config {
        public String tag;
        public String setting;
        public String intentAction;
        public String permission;
        public String noun;
        public int warningDialogTitle;
        public int warningDialogSummary;
        public int emptyText;
        public final String tag;
        public final String setting;
        public final String intentAction;
        public final String permission;
        public final String noun;
        public final int warningDialogTitle;
        public final int warningDialogSummary;
        public final int emptyText;

        private Config(String tag, String setting, String intentAction, String permission,
                String noun, int warningDialogTitle, int warningDialogSummary, int emptyText) {
            this.tag = tag;
            this.setting = setting;
            this.intentAction = intentAction;
            this.permission = permission;
            this.noun = noun;
            this.warningDialogTitle = warningDialogTitle;
            this.warningDialogSummary = warningDialogSummary;
            this.emptyText = emptyText;
        }

        public static class Builder{
            private String mTag;
            private String mSetting;
            private String mIntentAction;
            private String mPermission;
            private String mNoun;
            private int mWarningDialogTitle;
            private int mWarningDialogSummary;
            private int mEmptyText;

            public Builder setTag(String tag) {
                mTag = tag;
                return this;
            }

            public Builder setSetting(String setting) {
                mSetting = setting;
                return this;
            }

            public Builder setIntentAction(String intentAction) {
                mIntentAction = intentAction;
                return this;
            }

            public Builder setPermission(String permission) {
                mPermission = permission;
                return this;
            }

            public Builder setNoun(String noun) {
                mNoun = noun;
                return this;
            }

            public Builder setWarningDialogTitle(int warningDialogTitle) {
                mWarningDialogTitle = warningDialogTitle;
                return this;
            }

            public Builder setWarningDialogSummary(int warningDialogSummary) {
                mWarningDialogSummary = warningDialogSummary;
                return this;
            }

            public Builder setEmptyText(int emptyText) {
                mEmptyText = emptyText;
                return this;
            }

            public Config build() {
                return new Config(mTag, mSetting, mIntentAction, mPermission, mNoun,
                        mWarningDialogTitle, mWarningDialogSummary, mEmptyText);
            }
        }
    }

}
+0 −196
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settings.utils;

import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Slog;

import com.android.settings.utils.ManagedServiceSettings.Config;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

public class ServiceListing {
    private final ContentResolver mContentResolver;
    private final Context mContext;
    private final Config mConfig;
    private final HashSet<ComponentName> mEnabledServices = new HashSet<ComponentName>();
    private final List<ServiceInfo> mServices = new ArrayList<ServiceInfo>();
    private final List<Callback> mCallbacks = new ArrayList<Callback>();

    private boolean mListening;

    public ServiceListing(Context context, Config config) {
        mContext = context;
        mConfig = config;
        mContentResolver = context.getContentResolver();
    }

    public void addCallback(Callback callback) {
        mCallbacks.add(callback);
    }

    public void removeCallback(Callback callback) {
        mCallbacks.remove(callback);
    }

    public void setListening(boolean listening) {
        if (mListening == listening) return;
        mListening = listening;
        if (mListening) {
            // listen for package changes
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_PACKAGE_ADDED);
            filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
            filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
            filter.addDataScheme("package");
            mContext.registerReceiver(mPackageReceiver, filter);
            mContentResolver.registerContentObserver(Settings.Secure.getUriFor(mConfig.setting),
                    false, mSettingsObserver);
        } else {
            mContext.unregisterReceiver(mPackageReceiver);
            mContentResolver.unregisterContentObserver(mSettingsObserver);
        }
    }

    public static int getEnabledServicesCount(Config config, Context context) {
        final String flat = Settings.Secure.getString(context.getContentResolver(), config.setting);
        if (flat == null || "".equals(flat)) return 0;
        final String[] components = flat.split(":");
        return components.length;
    }

    public static int getServicesCount(Config c, PackageManager pm) {
        return getServices(c, null, pm);
    }

    protected static int getServices(Config c, List<ServiceInfo> list, PackageManager pm) {
        int services = 0;
        if (list != null) {
            list.clear();
        }
        final int user = ActivityManager.getCurrentUser();

        List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
                new Intent(c.intentAction),
                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
                user);

        for (int i = 0, count = installedServices.size(); i < count; i++) {
            ResolveInfo resolveInfo = installedServices.get(i);
            ServiceInfo info = resolveInfo.serviceInfo;

            if (!c.permission.equals(info.permission)) {
                Slog.w(c.tag, "Skipping " + c.noun + " service "
                        + info.packageName + "/" + info.name
                        + ": it does not require the permission "
                        + c.permission);
                continue;
            }
            if (list != null) {
                list.add(info);
            }
            services++;
        }
        return services;
    }

    private void saveEnabledServices() {
        StringBuilder sb = null;
        for (ComponentName cn : mEnabledServices) {
            if (sb == null) {
                sb = new StringBuilder();
            } else {
                sb.append(':');
            }
            sb.append(cn.flattenToString());
        }
        Settings.Secure.putString(mContentResolver, mConfig.setting,
                sb != null ? sb.toString() : "");
    }

    private void loadEnabledServices() {
        mEnabledServices.clear();
        final String flat = Settings.Secure.getString(mContentResolver, mConfig.setting);
        if (flat != null && !"".equals(flat)) {
            final String[] names = flat.split(":");
            for (int i = 0; i < names.length; i++) {
                final ComponentName cn = ComponentName.unflattenFromString(names[i]);
                if (cn != null) {
                    mEnabledServices.add(cn);
                }
            }
        }
    }

    public List<ServiceInfo> reload() {
        loadEnabledServices();
        getServices(mConfig, mServices, mContext.getPackageManager());
        for (Callback callback : mCallbacks) {
            callback.onServicesReloaded(mServices);
        }
        return mServices;
    }

    public boolean isEnabled(ComponentName cn) {
        return mEnabledServices.contains(cn);
    }

    public void setEnabled(ComponentName cn, boolean enabled) {
        if (enabled) {
            mEnabledServices.add(cn);
        } else {
            mEnabledServices.remove(cn);
        }
        saveEnabledServices();
    }

    private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
        @Override
        public void onChange(boolean selfChange, Uri uri) {
            reload();
        }
    };

    private final BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            reload();
        }
    };

    public interface Callback {
        void onServicesReloaded(List<ServiceInfo> services);
    }
}