Merge changes I1149cb5b,Ib89a17aa

* changes:
  Allow condition providers to specify a rule instance limit.
  Verify zen rule owners before persisting rules.
This commit is contained in:
Julia Reynolds
2016-01-15 16:43:57 +00:00
committed by Android (Google) Code Review
8 changed files with 106 additions and 23 deletions

View File

@@ -33620,6 +33620,7 @@ package android.service.notification {
method public abstract void onUnsubscribe(android.net.Uri);
field public static final java.lang.String EXTRA_RULE_ID = "android.content.automatic.ruleId";
field public static final java.lang.String META_DATA_CONFIGURATION_ACTIVITY = "android.service.zen.automatic.configurationActivity";
field public static final java.lang.String META_DATA_RULE_INSTANCE_LIMIT = "android.service.zen.automatic.ruleInstanceLimit";
field public static final java.lang.String META_DATA_RULE_TYPE = "android.service.zen.automatic.ruleType";
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
}

View File

@@ -35766,6 +35766,7 @@ package android.service.notification {
method public abstract void onUnsubscribe(android.net.Uri);
field public static final java.lang.String EXTRA_RULE_ID = "android.content.automatic.ruleId";
field public static final java.lang.String META_DATA_CONFIGURATION_ACTIVITY = "android.service.zen.automatic.configurationActivity";
field public static final java.lang.String META_DATA_RULE_INSTANCE_LIMIT = "android.service.zen.automatic.ruleInstanceLimit";
field public static final java.lang.String META_DATA_RULE_TYPE = "android.service.zen.automatic.ruleType";
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
}

View File

@@ -33634,6 +33634,7 @@ package android.service.notification {
method public abstract void onUnsubscribe(android.net.Uri);
field public static final java.lang.String EXTRA_RULE_ID = "android.content.automatic.ruleId";
field public static final java.lang.String META_DATA_CONFIGURATION_ACTIVITY = "android.service.zen.automatic.configurationActivity";
field public static final java.lang.String META_DATA_RULE_INSTANCE_LIMIT = "android.service.zen.automatic.ruleInstanceLimit";
field public static final java.lang.String META_DATA_RULE_TYPE = "android.service.zen.automatic.ruleType";
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
}

View File

@@ -103,6 +103,7 @@ interface INotificationManager
boolean updateAutomaticZenRule(in AutomaticZenRule automaticZenRule);
boolean removeAutomaticZenRule(String id);
boolean removeAutomaticZenRules(String packageName);
int getRuleInstanceCount(in ComponentName owner);
byte[] getBackupPayload(int user);
void applyRestore(in byte[] payload, int user);

View File

@@ -379,6 +379,18 @@ public class NotificationManager
return null;
}
/**
* @hide
*/
public int getRuleInstanceCount(ComponentName owner) {
INotificationManager service = getService();
try {
return service.getRuleInstanceCount(owner);
} catch (RemoteException e) {
}
return 0;
}
/**
* Returns AutomaticZenRules owned by the caller.
*

View File

@@ -84,6 +84,13 @@ public abstract class ConditionProviderService extends Service {
public static final String META_DATA_CONFIGURATION_ACTIVITY =
"android.service.zen.automatic.configurationActivity";
/**
* The name of the {@code meta-data} tag containing the maximum number of rule instances that
* can be created for this rule type. Omit or enter a value <= 0 to allow unlimited instances.
*/
public static final String META_DATA_RULE_INSTANCE_LIMIT =
"android.service.zen.automatic.ruleInstanceLimit";
/**
* A String rule id extra passed to {@link #META_DATA_CONFIGURATION_ACTIVITY}.
*/

View File

@@ -1726,6 +1726,14 @@ public class NotificationManagerService extends SystemService {
return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
}
@Override
public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
Preconditions.checkNotNull(owner, "Owner is null");
enforceSystemOrSystemUI("getRuleInstanceCount");
return mZenModeHelper.getCurrentInstanceCount(owner);
}
@Override
public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
enforcePolicyAccess(pkg, "setInterruptionFilter");

View File

@@ -27,7 +27,10 @@ import android.app.NotificationManager.Policy;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.database.ContentObserver;
@@ -45,7 +48,7 @@ import android.os.Process;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings.Global;
import android.service.notification.IConditionListener;
import android.service.notification.ConditionProviderService;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.EventInfo;
import android.service.notification.ZenModeConfig.ScheduleInfo;
@@ -91,6 +94,7 @@ public class ZenModeHelper {
private final ZenModeConditions mConditions;
private final SparseArray<ZenModeConfig> mConfigs = new SparseArray<>();
private final Metrics mMetrics = new Metrics();
private final ConditionProviders.Config mServiceConfig;
private int mZenMode;
private int mUser = UserHandle.USER_SYSTEM;
@@ -113,6 +117,7 @@ public class ZenModeHelper {
mSettingsObserver.observe();
mFiltering = new ZenModeFiltering(mContext);
mConditions = new ZenModeConditions(this, conditionProviders);
mServiceConfig = conditionProviders.getConfig();
}
public Looper getLooper() {
@@ -197,7 +202,7 @@ public class ZenModeHelper {
config.user = user;
}
synchronized (mConfig) {
setConfig(config, "onUserSwitched");
setConfigLocked(config, "onUserSwitched");
}
cleanUpZenRules();
}
@@ -257,22 +262,34 @@ public class ZenModeHelper {
}
public AutomaticZenRule addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
if (!TextUtils.isEmpty(automaticZenRule.getId())) {
throw new IllegalArgumentException("Rule already exists");
}
if (!isSystemRule(automaticZenRule)) {
ServiceInfo owner = getServiceInfo(automaticZenRule.getOwner());
if (owner == null) {
throw new IllegalArgumentException("Owner is not a condition provider service");
}
final int ruleInstanceLimit = owner.metaData.getInt(
ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1);
if (ruleInstanceLimit > 0 && ruleInstanceLimit
< (getCurrentInstanceCount(automaticZenRule.getOwner()) + 1)) {
throw new IllegalArgumentException("Rule instance limit exceeded");
}
}
ZenModeConfig newConfig;
synchronized (mConfig) {
if (mConfig == null) return null;
if (DEBUG) {
Log.d(TAG,
"addAutomaticZenRule zenRule= " + automaticZenRule + " reason=" + reason);
}
if (!TextUtils.isEmpty(automaticZenRule.getId())) {
throw new IllegalArgumentException("Rule already exists");
Log.d(TAG, "addAutomaticZenRule rule= " + automaticZenRule + " reason=" + reason);
}
newConfig = mConfig.copy();
ZenRule rule = new ZenRule();
populateZenRule(automaticZenRule, rule, true);
newConfig.automaticRules.put(rule.id, rule);
if (setConfig(newConfig, reason, true)) {
if (setConfigLocked(newConfig, reason, true)) {
return createAutomaticZenRule(rule);
} else {
return null;
@@ -302,7 +319,7 @@ public class ZenModeHelper {
}
populateZenRule(automaticZenRule, rule, false);
newConfig.automaticRules.put(ruleId, rule);
return setConfig(newConfig, reason, true);
return setConfigLocked(newConfig, reason, true);
}
}
@@ -320,7 +337,7 @@ public class ZenModeHelper {
throw new SecurityException(
"Cannot delete rules not owned by your condition provider");
}
return setConfig(newConfig, reason, true);
return setConfigLocked(newConfig, reason, true);
}
}
@@ -336,10 +353,22 @@ public class ZenModeHelper {
newConfig.automaticRules.removeAt(i);
}
}
return setConfig(newConfig, reason, true);
return setConfigLocked(newConfig, reason, true);
}
}
public int getCurrentInstanceCount(ComponentName owner) {
int count = 0;
synchronized (mConfig) {
for (ZenRule rule : mConfig.automaticRules.values()) {
if (rule.component != null && rule.component.equals(owner)) {
count++;
}
}
}
return count;
}
public boolean canManageAutomaticZenRule(ZenRule rule) {
final int callingUid = Binder.getCallingUid();
if (callingUid == 0 || callingUid == Process.SYSTEM_UID) {
@@ -361,6 +390,29 @@ public class ZenModeHelper {
}
}
private boolean isSystemRule(AutomaticZenRule rule) {
return ZenModeConfig.SYSTEM_AUTHORITY.equals(rule.getOwner().getPackageName());
}
private ServiceInfo getServiceInfo(ComponentName owner) {
Intent queryIntent = new Intent();
queryIntent.setComponent(owner);
List<ResolveInfo> installedServices = mPm.queryIntentServicesAsUser(
queryIntent,
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
UserHandle.getCallingUserId());
if (installedServices != null) {
for (int i = 0, count = installedServices.size(); i < count; i++) {
ResolveInfo resolveInfo = installedServices.get(i);
ServiceInfo info = resolveInfo.serviceInfo;
if (mServiceConfig.bindPermission.equals(info.permission)) {
return info;
}
}
}
return null;
}
private void populateZenRule(AutomaticZenRule automaticZenRule, ZenRule rule, boolean isNew) {
if (isNew) {
rule.id = ZenModeConfig.newRuleId();
@@ -413,7 +465,7 @@ public class ZenModeHelper {
newRule.conditionId = conditionId;
newConfig.manualRule = newRule;
}
setConfig(newConfig, reason, setRingerMode);
setConfigLocked(newConfig, reason, setRingerMode);
}
}
@@ -478,7 +530,7 @@ public class ZenModeHelper {
}
if (DEBUG) Log.d(TAG, "readXml");
synchronized (mConfig) {
setConfig(config, "readXml");
setConfigLocked(config, "readXml");
}
}
}
@@ -507,7 +559,7 @@ public class ZenModeHelper {
synchronized (mConfig) {
final ZenModeConfig newConfig = mConfig.copy();
newConfig.applyNotificationPolicy(policy);
setConfig(newConfig, "setNotificationPolicy");
setConfigLocked(newConfig, "setNotificationPolicy");
}
}
@@ -530,7 +582,7 @@ public class ZenModeHelper {
}
}
}
setConfig(newConfig, "cleanUpZenRules");
setConfigLocked(newConfig, "cleanUpZenRules");
}
}
@@ -543,30 +595,30 @@ public class ZenModeHelper {
}
}
public boolean setConfig(ZenModeConfig config, String reason) {
return setConfig(config, reason, true /*setRingerMode*/);
public boolean setConfigLocked(ZenModeConfig config, String reason) {
return setConfigLocked(config, reason, true /*setRingerMode*/);
}
public void setConfigAsync(ZenModeConfig config, String reason) {
mHandler.postSetConfig(config, reason);
}
private boolean setConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
private boolean setConfigLocked(ZenModeConfig config, String reason, boolean setRingerMode) {
final long identity = Binder.clearCallingIdentity();
try {
if (config == null || !config.isValid()) {
Log.w(TAG, "Invalid config in setConfig; " + config);
Log.w(TAG, "Invalid config in setConfigLocked; " + config);
return false;
}
if (config.user != mUser) {
// simply store away for background users
mConfigs.put(config.user, config);
if (DEBUG) Log.d(TAG, "setConfig: store config for user " + config.user);
if (DEBUG) Log.d(TAG, "setConfigLocked: store config for user " + config.user);
return true;
}
mConditions.evaluateConfig(config, false /*processSubscriptions*/); // may modify config
mConfigs.put(config.user, config);
if (DEBUG) Log.d(TAG, "setConfig reason=" + reason, new Throwable());
if (DEBUG) Log.d(TAG, "setConfigLocked reason=" + reason, new Throwable());
ZenLog.traceConfig(reason, mConfig, config);
final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
getNotificationPolicy(config));
@@ -1041,7 +1093,7 @@ public class ZenModeHelper {
case MSG_SET_CONFIG:
ConfigMessageData configData = (ConfigMessageData)msg.obj;
synchronized (mConfig) {
setConfig(configData.config, configData.reason);
setConfigLocked(configData.config, configData.reason);
}
break;
}