Merge "resolve merge conflicts of 69c2907c63 to master."
diff --git a/api/current.txt b/api/current.txt
index 6d67fb9..e75ab1c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -33620,6 +33620,7 @@
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";
}
diff --git a/api/system-current.txt b/api/system-current.txt
index d4efb8c..49ff948 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -35766,6 +35766,7 @@
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";
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 57c735b..68f8a41 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -33634,6 +33634,7 @@
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";
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 633f699..368b8ef 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -103,6 +103,7 @@
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);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 9a3c820..faf5b11 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -380,6 +380,18 @@
}
/**
+ * @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.
*
* <p>
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index e875864..6935174 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -534,6 +534,24 @@
public static final String STRING_TYPE_WRIST_TILT_GESTURE = "android.sensor.wrist_tilt_gesture";
/**
+ * The current orientation of the device.
+ * <p>
+ * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
+ *
+ * @hide Expected to be used internally for auto-rotate and speaker rotation.
+ *
+ */
+ public static final int TYPE_DEVICE_ORIENTATION = 27;
+
+ /**
+ * A constant string describing a device orientation sensor type.
+ *
+ * @hide
+ * @see #TYPE_DEVICE_ORIENTATION
+ */
+ public static final String STRING_TYPE_DEVICE_ORIENTATION = "android.sensor.device_orientation";
+
+ /**
* A constant describing all sensor types.
*/
public static final int TYPE_ALL = -1;
@@ -618,6 +636,7 @@
1, // SENSOR_TYPE_GLANCE_GESTURE
1, // SENSOR_TYPE_PICK_UP_GESTURE
1, // SENSOR_TYPE_WRIST_TILT_GESTURE
+ 1, // SENSOR_TYPE_DEVICE_ORIENTATION
};
/**
@@ -939,6 +958,9 @@
case TYPE_TEMPERATURE:
mStringType = STRING_TYPE_TEMPERATURE;
return true;
+ case TYPE_DEVICE_ORIENTATION:
+ mStringType = STRING_TYPE_DEVICE_ORIENTATION;
+ return true;
default:
return false;
}
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 906c2a19..9937b2c 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -483,6 +483,20 @@
* on it. In earlier versions, this used to be always 3 which has changed now. </p>
*
* @see GeomagneticField
+ *
+ * <h4> {@link android.hardware.Sensor#TYPE_DEVICE_ORIENTATION
+ * Sensor.TYPE_DEVICE_ORIENTATION}:</h4>
+ * The current device orientation will be available in values[0]. The only
+ * available values are:
+ * <ul>
+ * <li> 0: device is in default orientation (Y axis is vertical and points up)
+ * <li> 1: device is rotated 90 degrees counter-clockwise from default
+ * orientation (X axis is vertical and points up)
+ * <li> 2: device is rotated 180 degrees from default orientation (Y axis is
+ * vertical and points down)
+ * <li> 3: device is rotated 90 degrees clockwise from default orientation (X axis
+ * is vertical and points down)
+ * </ul>
*/
public final float[] values;
diff --git a/core/java/android/service/notification/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java
index 88bd283..eff09d6 100644
--- a/core/java/android/service/notification/ConditionProviderService.java
+++ b/core/java/android/service/notification/ConditionProviderService.java
@@ -85,6 +85,13 @@
"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}.
*/
public static final String EXTRA_RULE_ID = "android.content.automatic.ruleId";
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 018bf2d..b1fe68c 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1727,6 +1727,14 @@
}
@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");
final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index f7043a6..1d91fb7 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -27,7 +27,10 @@
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.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 @@
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 @@
mSettingsObserver.observe();
mFiltering = new ZenModeFiltering(mContext);
mConditions = new ZenModeConditions(this, conditionProviders);
+ mServiceConfig = conditionProviders.getConfig();
}
public Looper getLooper() {
@@ -197,7 +202,7 @@
config.user = user;
}
synchronized (mConfig) {
- setConfig(config, "onUserSwitched");
+ setConfigLocked(config, "onUserSwitched");
}
cleanUpZenRules();
}
@@ -257,22 +262,34 @@
}
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 @@
}
populateZenRule(automaticZenRule, rule, false);
newConfig.automaticRules.put(ruleId, rule);
- return setConfig(newConfig, reason, true);
+ return setConfigLocked(newConfig, reason, true);
}
}
@@ -320,7 +337,7 @@
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 @@
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 @@
}
}
+ 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 @@
newRule.conditionId = conditionId;
newConfig.manualRule = newRule;
}
- setConfig(newConfig, reason, setRingerMode);
+ setConfigLocked(newConfig, reason, setRingerMode);
}
}
@@ -478,7 +530,7 @@
}
if (DEBUG) Log.d(TAG, "readXml");
synchronized (mConfig) {
- setConfig(config, "readXml");
+ setConfigLocked(config, "readXml");
}
}
}
@@ -507,7 +559,7 @@
synchronized (mConfig) {
final ZenModeConfig newConfig = mConfig.copy();
newConfig.applyNotificationPolicy(policy);
- setConfig(newConfig, "setNotificationPolicy");
+ setConfigLocked(newConfig, "setNotificationPolicy");
}
}
@@ -530,7 +582,7 @@
}
}
}
- setConfig(newConfig, "cleanUpZenRules");
+ setConfigLocked(newConfig, "cleanUpZenRules");
}
}
@@ -543,30 +595,30 @@
}
}
- 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 @@
case MSG_SET_CONFIG:
ConfigMessageData configData = (ConfigMessageData)msg.obj;
synchronized (mConfig) {
- setConfig(configData.config, configData.reason);
+ setConfigLocked(configData.config, configData.reason);
}
break;
}