Move ServiceListing to SettingsLib

Also tidy things up a bit

Bug: 70902607
Test: RunSettingsRoboTests
Change-Id: Id641beb601513bb4e34a098bf2729eb98954175d
This commit is contained in:
Tony Mantler
2017-12-20 15:54:01 -08:00
parent 79f4be2e5a
commit 09d2d71760
5 changed files with 141 additions and 287 deletions

View File

@@ -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() {

View File

@@ -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 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 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 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,13 +117,10 @@ 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() {
if (!parent.mNm.isNotificationPolicyAccessGrantedForPackage(
cn.getPackageName())) {
parent.mNm.removeAutomaticZenRules(cn.getPackageName());
}
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) {
// pass
}
(dialog, id) -> {
// pass
})
.create();
}

View File

@@ -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();
}
/**

View File

@@ -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) {
final boolean enable = (boolean) newValue;
return setEnabled(cn, summary, enable);
}
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) {
// pass
}
(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);
}
}
}
}

View File

@@ -1,196 +0,0 @@
/*
* 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);
}
}