am cf21f77a: Merge "Implement long-term condition subscriptions."
* commit 'cf21f77a6973e292714af879c36706aa51a8e790': Implement long-term condition subscriptions.
This commit is contained in:
@@ -58,6 +58,8 @@ interface INotificationManager
|
||||
ZenModeConfig getZenModeConfig();
|
||||
boolean setZenModeConfig(in ZenModeConfig config);
|
||||
oneway void notifyConditions(String pkg, in IConditionProvider provider, in Condition[] conditions);
|
||||
oneway void requestZenModeConditions(in IConditionListener callback, boolean requested);
|
||||
oneway void requestZenModeConditions(in IConditionListener callback, int relevance);
|
||||
oneway void setZenModeCondition(in Uri conditionId);
|
||||
oneway void setAutomaticZenModeConditions(in Uri[] conditionIds);
|
||||
Condition[] getAutomaticZenModeConditions();
|
||||
}
|
||||
@@ -71,7 +71,7 @@ public class Condition implements Parcelable {
|
||||
dest.writeParcelable(id, 0);
|
||||
dest.writeString(caption);
|
||||
dest.writeInt(state);
|
||||
dest.writeInt(flags);
|
||||
dest.writeInt(this.flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,6 +92,14 @@ public class Condition implements Parcelable {
|
||||
throw new IllegalArgumentException("state is invalid: " + state);
|
||||
}
|
||||
|
||||
public static String relevanceToString(int flags) {
|
||||
final boolean now = (flags & FLAG_RELEVANT_NOW) != 0;
|
||||
final boolean always = (flags & FLAG_RELEVANT_ALWAYS) != 0;
|
||||
if (!now && !always) return "NONE";
|
||||
if (now && always) return "NOW, ALWAYS";
|
||||
return now ? "NOW" : "ALWAYS";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Condition)) return false;
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.service.notification;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
@@ -25,6 +27,8 @@ import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -51,6 +55,10 @@ public class ZenModeConfig implements Parcelable {
|
||||
private static final String SLEEP_ATT_END_HR = "endHour";
|
||||
private static final String SLEEP_ATT_END_MIN = "endMin";
|
||||
|
||||
private static final String CONDITION_TAG = "condition";
|
||||
private static final String CONDITION_ATT_COMPONENT = "component";
|
||||
private static final String CONDITION_ATT_ID = "id";
|
||||
|
||||
public boolean allowCalls;
|
||||
public boolean allowMessages;
|
||||
|
||||
@@ -59,6 +67,8 @@ public class ZenModeConfig implements Parcelable {
|
||||
public int sleepStartMinute;
|
||||
public int sleepEndHour;
|
||||
public int sleepEndMinute;
|
||||
public ComponentName[] conditionComponents;
|
||||
public Uri[] conditionIds;
|
||||
|
||||
public ZenModeConfig() { }
|
||||
|
||||
@@ -72,6 +82,16 @@ public class ZenModeConfig implements Parcelable {
|
||||
sleepStartMinute = source.readInt();
|
||||
sleepEndHour = source.readInt();
|
||||
sleepEndMinute = source.readInt();
|
||||
int len = source.readInt();
|
||||
if (len > 0) {
|
||||
conditionComponents = new ComponentName[len];
|
||||
source.readTypedArray(conditionComponents, ComponentName.CREATOR);
|
||||
}
|
||||
len = source.readInt();
|
||||
if (len > 0) {
|
||||
conditionIds = new Uri[len];
|
||||
source.readTypedArray(conditionIds, Uri.CREATOR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -88,6 +108,18 @@ public class ZenModeConfig implements Parcelable {
|
||||
dest.writeInt(sleepStartMinute);
|
||||
dest.writeInt(sleepEndHour);
|
||||
dest.writeInt(sleepEndMinute);
|
||||
if (conditionComponents != null && conditionComponents.length > 0) {
|
||||
dest.writeInt(conditionComponents.length);
|
||||
dest.writeTypedArray(conditionComponents, 0);
|
||||
} else {
|
||||
dest.writeInt(0);
|
||||
}
|
||||
if (conditionIds != null && conditionIds.length > 0) {
|
||||
dest.writeInt(conditionIds.length);
|
||||
dest.writeTypedArray(conditionIds, 0);
|
||||
} else {
|
||||
dest.writeInt(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,6 +130,10 @@ public class ZenModeConfig implements Parcelable {
|
||||
.append(",sleepMode=").append(sleepMode)
|
||||
.append(",sleepStart=").append(sleepStartHour).append('.').append(sleepStartMinute)
|
||||
.append(",sleepEnd=").append(sleepEndHour).append('.').append(sleepEndMinute)
|
||||
.append(",conditionComponents=")
|
||||
.append(conditionComponents == null ? null : TextUtils.join(",", conditionComponents))
|
||||
.append(",conditionIds=")
|
||||
.append(conditionIds == null ? null : TextUtils.join(",", conditionIds))
|
||||
.append(']').toString();
|
||||
}
|
||||
|
||||
@@ -112,13 +148,16 @@ public class ZenModeConfig implements Parcelable {
|
||||
&& other.sleepStartHour == sleepStartHour
|
||||
&& other.sleepStartMinute == sleepStartMinute
|
||||
&& other.sleepEndHour == sleepEndHour
|
||||
&& other.sleepEndMinute == sleepEndMinute;
|
||||
&& other.sleepEndMinute == sleepEndMinute
|
||||
&& Objects.deepEquals(other.conditionComponents, conditionComponents)
|
||||
&& Objects.deepEquals(other.conditionIds, conditionIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(allowCalls, allowMessages, sleepMode, sleepStartHour,
|
||||
sleepStartMinute, sleepEndHour, sleepEndMinute);
|
||||
sleepStartMinute, sleepEndHour, sleepEndMinute,
|
||||
Arrays.hashCode(conditionComponents), Arrays.hashCode(conditionIds));
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
@@ -136,9 +175,18 @@ public class ZenModeConfig implements Parcelable {
|
||||
if (!ZEN_TAG.equals(tag)) return null;
|
||||
final ZenModeConfig rt = new ZenModeConfig();
|
||||
final int version = Integer.parseInt(parser.getAttributeValue(null, ZEN_ATT_VERSION));
|
||||
final ArrayList<ComponentName> conditionComponents = new ArrayList<ComponentName>();
|
||||
final ArrayList<Uri> conditionIds = new ArrayList<Uri>();
|
||||
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
|
||||
tag = parser.getName();
|
||||
if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) return rt;
|
||||
if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) {
|
||||
if (!conditionComponents.isEmpty()) {
|
||||
rt.conditionComponents = conditionComponents
|
||||
.toArray(new ComponentName[conditionComponents.size()]);
|
||||
rt.conditionIds = conditionIds.toArray(new Uri[conditionIds.size()]);
|
||||
}
|
||||
return rt;
|
||||
}
|
||||
if (type == XmlPullParser.START_TAG) {
|
||||
if (ALLOW_TAG.equals(tag)) {
|
||||
rt.allowCalls = safeBoolean(parser, ALLOW_ATT_CALLS, false);
|
||||
@@ -155,10 +203,18 @@ public class ZenModeConfig implements Parcelable {
|
||||
rt.sleepStartMinute = isValidMinute(startMinute) ? startMinute : 0;
|
||||
rt.sleepEndHour = isValidHour(endHour) ? endHour : 0;
|
||||
rt.sleepEndMinute = isValidMinute(endMinute) ? endMinute : 0;
|
||||
} else if (CONDITION_TAG.equals(tag)) {
|
||||
final ComponentName component =
|
||||
safeComponentName(parser, CONDITION_ATT_COMPONENT);
|
||||
final Uri conditionId = safeUri(parser, CONDITION_ATT_ID);
|
||||
if (component != null && conditionId != null) {
|
||||
conditionComponents.add(component);
|
||||
conditionIds.add(conditionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return rt;
|
||||
throw new IllegalStateException("Failed to reach END_DOCUMENT");
|
||||
}
|
||||
|
||||
public void writeXml(XmlSerializer out) throws IOException {
|
||||
@@ -180,6 +236,16 @@ public class ZenModeConfig implements Parcelable {
|
||||
out.attribute(null, SLEEP_ATT_END_MIN, Integer.toString(sleepEndMinute));
|
||||
out.endTag(null, SLEEP_TAG);
|
||||
|
||||
if (conditionComponents != null && conditionIds != null
|
||||
&& conditionComponents.length == conditionIds.length) {
|
||||
for (int i = 0; i < conditionComponents.length; i++) {
|
||||
out.startTag(null, CONDITION_TAG);
|
||||
out.attribute(null, CONDITION_ATT_COMPONENT,
|
||||
conditionComponents[i].flattenToString());
|
||||
out.attribute(null, CONDITION_ATT_ID, conditionIds[i].toString());
|
||||
out.endTag(null, CONDITION_TAG);
|
||||
}
|
||||
}
|
||||
out.endTag(null, ZEN_TAG);
|
||||
}
|
||||
|
||||
@@ -203,6 +269,18 @@ public class ZenModeConfig implements Parcelable {
|
||||
return Integer.valueOf(val);
|
||||
}
|
||||
|
||||
private static ComponentName safeComponentName(XmlPullParser parser, String att) {
|
||||
final String val = parser.getAttributeValue(null, att);
|
||||
if (TextUtils.isEmpty(val)) return null;
|
||||
return ComponentName.unflattenFromString(val);
|
||||
}
|
||||
|
||||
private static Uri safeUri(XmlPullParser parser, String att) {
|
||||
final String val = parser.getAttributeValue(null, att);
|
||||
if (TextUtils.isEmpty(val)) return null;
|
||||
return Uri.parse(val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
|
||||
@@ -58,7 +58,7 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter {
|
||||
mNoMan = INotificationManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
|
||||
try {
|
||||
mNoMan.requestZenModeConditions(mListener, true /*requested*/);
|
||||
mNoMan.requestZenModeConditions(mListener, Condition.FLAG_RELEVANT_NOW);
|
||||
} catch (RemoteException e) {
|
||||
// noop
|
||||
}
|
||||
@@ -98,7 +98,7 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter {
|
||||
@Override
|
||||
public void dispose() {
|
||||
try {
|
||||
mNoMan.requestZenModeConditions(mListener, false /*requested*/);
|
||||
mNoMan.requestZenModeConditions(mListener, 0 /*none*/);
|
||||
} catch (RemoteException e) {
|
||||
// noop
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.server.notification;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
@@ -28,31 +29,31 @@ import android.service.notification.Condition;
|
||||
import android.service.notification.ConditionProviderService;
|
||||
import android.service.notification.IConditionListener;
|
||||
import android.service.notification.IConditionProvider;
|
||||
import android.service.notification.ZenModeConfig;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import libcore.util.Objects;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ConditionProviders extends ManagedServices {
|
||||
private static final Condition[] NO_CONDITIONS = new Condition[0];
|
||||
|
||||
private final ZenModeHelper mZenModeHelper;
|
||||
private final ArrayMap<IBinder, IConditionListener> mListeners
|
||||
= new ArrayMap<IBinder, IConditionListener>();
|
||||
private final ArrayMap<Uri, ManagedServiceInfo> mConditions
|
||||
= new ArrayMap<Uri, ManagedServiceInfo>();
|
||||
|
||||
private Uri mCurrentConditionId;
|
||||
private final ArrayList<ConditionRecord> mRecords = new ArrayList<ConditionRecord>();
|
||||
|
||||
public ConditionProviders(Context context, Handler handler,
|
||||
UserProfiles userProfiles, ZenModeHelper zenModeHelper) {
|
||||
super(context, handler, new Object(), userProfiles);
|
||||
mZenModeHelper = zenModeHelper;
|
||||
mZenModeHelper.addCallback(new ZenModeHelperCallback());
|
||||
loadZenConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -71,20 +72,13 @@ public class ConditionProviders extends ManagedServices {
|
||||
public void dump(PrintWriter pw) {
|
||||
super.dump(pw);
|
||||
synchronized(mMutex) {
|
||||
pw.print(" mCurrentConditionId="); pw.println(mCurrentConditionId);
|
||||
pw.print(" mListeners("); pw.print(mListeners.size()); pw.println("):");
|
||||
for (int i = 0; i < mListeners.size(); i++) {
|
||||
pw.print(" "); pw.println(mListeners.keyAt(i));
|
||||
}
|
||||
pw.print(" mConditions("); pw.print(mConditions.size()); pw.println("):");
|
||||
for (int i = 0; i < mConditions.size(); i++) {
|
||||
pw.print(" "); pw.print(mConditions.keyAt(i));
|
||||
final ManagedServiceInfo info = mConditions.valueAt(i);
|
||||
pw.print(" -> "); pw.print(info.component);
|
||||
if (!mServices.contains(info)) {
|
||||
pw.print(" (orphan)");
|
||||
}
|
||||
pw.println();
|
||||
pw.print(" mRecords("); pw.print(mRecords.size()); pw.println("):");
|
||||
for (int i = 0; i < mRecords.size(); i++) {
|
||||
pw.print(" "); pw.println(mRecords.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,29 +89,49 @@ public class ConditionProviders extends ManagedServices {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onServiceAdded(IInterface service) {
|
||||
Slog.d(TAG, "onServiceAdded " + service);
|
||||
final IConditionProvider provider = (IConditionProvider) service;
|
||||
protected void onServiceAdded(ManagedServiceInfo info) {
|
||||
Slog.d(TAG, "onServiceAdded " + info);
|
||||
final IConditionProvider provider = provider(info);
|
||||
try {
|
||||
provider.onConnected();
|
||||
} catch (RemoteException e) {
|
||||
// we tried
|
||||
}
|
||||
synchronized (mMutex) {
|
||||
final int N = mRecords.size();
|
||||
for(int i = 0; i < N; i++) {
|
||||
final ConditionRecord r = mRecords.get(i);
|
||||
if (!r.component.equals(info.component)) continue;
|
||||
r.info = info;
|
||||
// if automatic, auto-subscribe
|
||||
if (r.isAutomatic) {
|
||||
try {
|
||||
final Uri id = r.id;
|
||||
if (DEBUG) Slog.d(TAG, "Auto-subscribing to configured condition " + id);
|
||||
provider.onSubscribe(id);
|
||||
} catch (RemoteException e) {
|
||||
// we tried
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
|
||||
if (removed == null) return;
|
||||
if (mCurrentConditionId != null) {
|
||||
if (removed.equals(mConditions.get(mCurrentConditionId))) {
|
||||
mCurrentConditionId = null;
|
||||
for (int i = mRecords.size() - 1; i >= 0; i--) {
|
||||
final ConditionRecord r = mRecords.get(i);
|
||||
if (!r.component.equals(removed.component)) continue;
|
||||
if (r.isManual) {
|
||||
// removing the current manual condition, exit zen
|
||||
mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF);
|
||||
}
|
||||
}
|
||||
for (int i = mConditions.size() - 1; i >= 0; i--) {
|
||||
if (removed.equals(mConditions.valueAt(i))) {
|
||||
mConditions.removeAt(i);
|
||||
if (r.isAutomatic) {
|
||||
// removing an automatic condition, exit zen
|
||||
mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF);
|
||||
}
|
||||
mRecords.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,14 +141,15 @@ public class ConditionProviders extends ManagedServices {
|
||||
}
|
||||
}
|
||||
|
||||
public void requestZenModeConditions(IConditionListener callback, boolean requested) {
|
||||
public void requestZenModeConditions(IConditionListener callback, int relevance) {
|
||||
synchronized(mMutex) {
|
||||
if (DEBUG) Slog.d(TAG, "requestZenModeConditions callback=" + callback
|
||||
+ " requested=" + requested);
|
||||
+ " relevance=" + Condition.relevanceToString(relevance));
|
||||
if (callback == null) return;
|
||||
if (requested) {
|
||||
relevance = relevance & (Condition.FLAG_RELEVANT_NOW | Condition.FLAG_RELEVANT_ALWAYS);
|
||||
if (relevance != 0) {
|
||||
mListeners.put(callback.asBinder(), callback);
|
||||
requestConditionsLocked(Condition.FLAG_RELEVANT_NOW);
|
||||
requestConditionsLocked(relevance);
|
||||
} else {
|
||||
mListeners.remove(callback.asBinder());
|
||||
if (mListeners.isEmpty()) {
|
||||
@@ -144,25 +159,51 @@ public class ConditionProviders extends ManagedServices {
|
||||
}
|
||||
}
|
||||
|
||||
private Condition[] validateConditions(String pkg, Condition[] conditions) {
|
||||
if (conditions == null || conditions.length == 0) return null;
|
||||
final int N = conditions.length;
|
||||
final ArrayMap<Uri, Condition> valid = new ArrayMap<Uri, Condition>(N);
|
||||
for (int i = 0; i < N; i++) {
|
||||
final Uri id = conditions[i].id;
|
||||
if (!Condition.isValidId(id, pkg)) {
|
||||
Slog.w(TAG, "Ignoring condition from " + pkg + " for invalid id: " + id);
|
||||
continue;
|
||||
}
|
||||
if (valid.containsKey(id)) {
|
||||
Slog.w(TAG, "Ignoring condition from " + pkg + " for duplicate id: " + id);
|
||||
continue;
|
||||
}
|
||||
valid.put(id, conditions[i]);
|
||||
}
|
||||
if (valid.size() == 0) return null;
|
||||
if (valid.size() == N) return conditions;
|
||||
final Condition[] rt = new Condition[valid.size()];
|
||||
for (int i = 0; i < rt.length; i++) {
|
||||
rt[i] = valid.valueAt(i);
|
||||
}
|
||||
return rt;
|
||||
}
|
||||
|
||||
private ConditionRecord getRecordLocked(Uri id, ComponentName component) {
|
||||
final int N = mRecords.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
final ConditionRecord r = mRecords.get(i);
|
||||
if (r.id.equals(id) && r.component.equals(component)) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
final ConditionRecord r = new ConditionRecord(id, component);
|
||||
mRecords.add(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
public void notifyConditions(String pkg, ManagedServiceInfo info, Condition[] conditions) {
|
||||
synchronized(mMutex) {
|
||||
if (DEBUG) Slog.d(TAG, "notifyConditions pkg=" + pkg + " info=" + info + " conditions="
|
||||
+ (conditions == null ? null : Arrays.asList(conditions)));
|
||||
conditions = validateConditions(pkg, conditions);
|
||||
if (conditions == null || conditions.length == 0) return;
|
||||
final int N = conditions.length;
|
||||
boolean valid = true;
|
||||
for (int i = 0; i < N; i++) {
|
||||
final Uri id = conditions[i].id;
|
||||
if (!Condition.isValidId(id, pkg)) {
|
||||
Slog.w(TAG, "Ignoring conditions from " + pkg + " for invalid id: " + id);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
if (!valid) return;
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
mConditions.put(conditions[i].id, info);
|
||||
}
|
||||
for (IConditionListener listener : mListeners.values()) {
|
||||
try {
|
||||
listener.onConditionsReceived(conditions);
|
||||
@@ -170,62 +211,154 @@ public class ConditionProviders extends ManagedServices {
|
||||
Slog.w(TAG, "Error sending conditions to listener " + listener, e);
|
||||
}
|
||||
}
|
||||
if (mCurrentConditionId != null) {
|
||||
for (int i = 0; i < N; i++) {
|
||||
final Condition c = conditions[i];
|
||||
if (!c.id.equals(mCurrentConditionId)) continue;
|
||||
if (c.state == Condition.STATE_TRUE || c.state == Condition.STATE_ERROR) {
|
||||
triggerExitLocked(c.state == Condition.STATE_ERROR);
|
||||
return;
|
||||
for (int i = 0; i < N; i++) {
|
||||
final Condition c = conditions[i];
|
||||
final ConditionRecord r = getRecordLocked(c.id, info.component);
|
||||
r.info = info;
|
||||
r.condition = c;
|
||||
// if manual, exit zen if false (or failed)
|
||||
if (r.isManual) {
|
||||
if (c.state == Condition.STATE_FALSE || c.state == Condition.STATE_ERROR) {
|
||||
final boolean failed = c.state == Condition.STATE_ERROR;
|
||||
if (failed) {
|
||||
Slog.w(TAG, "Exit zen: manual condition failed: " + c);
|
||||
} else if (DEBUG) {
|
||||
Slog.d(TAG, "Exit zen: manual condition false: " + c);
|
||||
}
|
||||
mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF);
|
||||
unsubscribeLocked(r);
|
||||
r.isManual = false;
|
||||
}
|
||||
}
|
||||
// if automatic, exit zen if false (or failed), enter zen if true
|
||||
if (r.isAutomatic) {
|
||||
if (c.state == Condition.STATE_FALSE || c.state == Condition.STATE_ERROR) {
|
||||
final boolean failed = c.state == Condition.STATE_ERROR;
|
||||
if (failed) {
|
||||
Slog.w(TAG, "Exit zen: automatic condition failed: " + c);
|
||||
} else if (DEBUG) {
|
||||
Slog.d(TAG, "Exit zen: automatic condition false: " + c);
|
||||
}
|
||||
mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF);
|
||||
} else if (c.state == Condition.STATE_TRUE) {
|
||||
Slog.d(TAG, "Enter zen: automatic condition true: " + c);
|
||||
mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_ON);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void triggerExitLocked(boolean error) {
|
||||
if (error) {
|
||||
Slog.w(TAG, "Zen mode exit condition failed");
|
||||
} else if (DEBUG) {
|
||||
Slog.d(TAG, "Zen mode exit condition triggered");
|
||||
}
|
||||
mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF);
|
||||
unsubscribeLocked(mCurrentConditionId);
|
||||
mCurrentConditionId = null;
|
||||
}
|
||||
|
||||
public void setZenModeCondition(Uri conditionId) {
|
||||
if (DEBUG) Slog.d(TAG, "setZenModeCondition " + conditionId);
|
||||
synchronized(mMutex) {
|
||||
if (DEBUG) Slog.d(TAG, "setZenModeCondition " + conditionId);
|
||||
if (Objects.equal(mCurrentConditionId, conditionId)) return;
|
||||
|
||||
if (mCurrentConditionId != null) {
|
||||
unsubscribeLocked(mCurrentConditionId);
|
||||
}
|
||||
if (conditionId != null) {
|
||||
final ManagedServiceInfo info = mConditions.get(conditionId);
|
||||
final IConditionProvider provider = provider(info);
|
||||
if (provider == null) return;
|
||||
try {
|
||||
provider.onSubscribe(conditionId);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Error subscribing to " + conditionId
|
||||
+ " from " + info.component, e);
|
||||
final int N = mRecords.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
final ConditionRecord r = mRecords.get(i);
|
||||
final boolean idEqual = r.id.equals(conditionId);
|
||||
if (r.isManual && !idEqual) {
|
||||
// was previous manual condition, unsubscribe
|
||||
unsubscribeLocked(r);
|
||||
r.isManual = false;
|
||||
} else if (idEqual && !r.isManual) {
|
||||
// is new manual condition, subscribe
|
||||
subscribeLocked(r);
|
||||
r.isManual = true;
|
||||
}
|
||||
}
|
||||
mCurrentConditionId = conditionId;
|
||||
}
|
||||
}
|
||||
|
||||
private void unsubscribeLocked(Uri conditionId) {
|
||||
final ManagedServiceInfo info = mConditions.get(mCurrentConditionId);
|
||||
final IConditionProvider provider = provider(info);
|
||||
if (provider == null) return;
|
||||
try {
|
||||
provider.onUnsubscribe(conditionId);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Error unsubscribing to " + conditionId + " from " + info.component, e);
|
||||
private void subscribeLocked(ConditionRecord r) {
|
||||
if (DEBUG) Slog.d(TAG, "subscribeLocked " + r);
|
||||
final IConditionProvider provider = provider(r);
|
||||
if (provider == null) {
|
||||
Slog.w(TAG, "subscribeLocked: no provider");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
provider.onSubscribe(r.id);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Error subscribing to " + r, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> ArraySet<T> safeSet(T... items) {
|
||||
final ArraySet<T> rt = new ArraySet<T>();
|
||||
if (items == null || items.length == 0) return rt;
|
||||
final int N = items.length;
|
||||
for (int i = 0; i < N; i++) {
|
||||
final T item = items[i];
|
||||
if (item != null) {
|
||||
rt.add(item);
|
||||
}
|
||||
}
|
||||
return rt;
|
||||
}
|
||||
|
||||
public void setAutomaticZenModeConditions(Uri[] conditionIds) {
|
||||
setAutomaticZenModeConditions(conditionIds, true /*save*/);
|
||||
}
|
||||
|
||||
private void setAutomaticZenModeConditions(Uri[] conditionIds, boolean save) {
|
||||
if (DEBUG) Slog.d(TAG, "setAutomaticZenModeConditions "
|
||||
+ (conditionIds == null ? null : Arrays.asList(conditionIds)));
|
||||
synchronized(mMutex) {
|
||||
final ArraySet<Uri> newIds = safeSet(conditionIds);
|
||||
final int N = mRecords.size();
|
||||
boolean changed = false;
|
||||
for (int i = 0; i < N; i++) {
|
||||
final ConditionRecord r = mRecords.get(i);
|
||||
final boolean automatic = newIds.contains(r.id);
|
||||
if (!r.isAutomatic && automatic) {
|
||||
// subscribe to new automatic
|
||||
subscribeLocked(r);
|
||||
r.isAutomatic = true;
|
||||
changed = true;
|
||||
} else if (r.isAutomatic && !automatic) {
|
||||
// unsubscribe from old automatic
|
||||
unsubscribeLocked(r);
|
||||
r.isAutomatic = false;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (save && changed) {
|
||||
saveZenConfigLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Condition[] getAutomaticZenModeConditions() {
|
||||
synchronized(mMutex) {
|
||||
final int N = mRecords.size();
|
||||
ArrayList<Condition> rt = null;
|
||||
for (int i = 0; i < N; i++) {
|
||||
final ConditionRecord r = mRecords.get(i);
|
||||
if (r.isAutomatic && r.condition != null) {
|
||||
if (rt == null) rt = new ArrayList<Condition>();
|
||||
rt.add(r.condition);
|
||||
}
|
||||
}
|
||||
return rt == null ? NO_CONDITIONS : rt.toArray(new Condition[rt.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
private void unsubscribeLocked(ConditionRecord r) {
|
||||
if (DEBUG) Slog.d(TAG, "unsubscribeLocked " + r);
|
||||
final IConditionProvider provider = provider(r);
|
||||
if (provider == null) {
|
||||
Slog.w(TAG, "unsubscribeLocked: no provider");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
provider.onUnsubscribe(r.id);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Error unsubscribing to " + r, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static IConditionProvider provider(ConditionRecord r) {
|
||||
return r == null ? null : provider(r.info);
|
||||
}
|
||||
|
||||
private static IConditionProvider provider(ManagedServiceInfo info) {
|
||||
@@ -244,20 +377,99 @@ public class ConditionProviders extends ManagedServices {
|
||||
}
|
||||
}
|
||||
|
||||
private void loadZenConfig() {
|
||||
final ZenModeConfig config = mZenModeHelper.getConfig();
|
||||
if (config == null) {
|
||||
if (DEBUG) Slog.d(TAG, "loadZenConfig: no config");
|
||||
return;
|
||||
}
|
||||
synchronized (mMutex) {
|
||||
if (config.conditionComponents == null || config.conditionIds == null
|
||||
|| config.conditionComponents.length != config.conditionIds.length) {
|
||||
if (DEBUG) Slog.d(TAG, "loadZenConfig: no conditions");
|
||||
setAutomaticZenModeConditions(null, false /*save*/);
|
||||
return;
|
||||
}
|
||||
final ArraySet<Uri> newIds = new ArraySet<Uri>();
|
||||
final int N = config.conditionComponents.length;
|
||||
for (int i = 0; i < N; i++) {
|
||||
final ComponentName component = config.conditionComponents[i];
|
||||
final Uri id = config.conditionIds[i];
|
||||
if (component != null && id != null) {
|
||||
getRecordLocked(id, component); // ensure record exists
|
||||
newIds.add(id);
|
||||
}
|
||||
}
|
||||
if (DEBUG) Slog.d(TAG, "loadZenConfig: N=" + N);
|
||||
setAutomaticZenModeConditions(newIds.toArray(new Uri[newIds.size()]), false /*save*/);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveZenConfigLocked() {
|
||||
ZenModeConfig config = mZenModeHelper.getConfig();
|
||||
if (config == null) return;
|
||||
config = config.copy();
|
||||
final ArrayList<ConditionRecord> automatic = new ArrayList<ConditionRecord>();
|
||||
final int automaticN = mRecords.size();
|
||||
for (int i = 0; i < automaticN; i++) {
|
||||
final ConditionRecord r = mRecords.get(i);
|
||||
if (r.isAutomatic) {
|
||||
automatic.add(r);
|
||||
}
|
||||
}
|
||||
if (automatic.isEmpty()) {
|
||||
config.conditionComponents = null;
|
||||
config.conditionIds = null;
|
||||
} else {
|
||||
final int N = automatic.size();
|
||||
config.conditionComponents = new ComponentName[N];
|
||||
config.conditionIds = new Uri[N];
|
||||
for (int i = 0; i < N; i++) {
|
||||
final ConditionRecord r = automatic.get(i);
|
||||
config.conditionComponents[i] = r.component;
|
||||
config.conditionIds[i] = r.id;
|
||||
}
|
||||
}
|
||||
if (DEBUG) Slog.d(TAG, "Setting zen config to: " + config);
|
||||
mZenModeHelper.setConfig(config);
|
||||
}
|
||||
|
||||
private class ZenModeHelperCallback extends ZenModeHelper.Callback {
|
||||
@Override
|
||||
void onConfigChanged() {
|
||||
loadZenConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
void onZenModeChanged() {
|
||||
final int mode = mZenModeHelper.getZenMode();
|
||||
if (mode == Global.ZEN_MODE_OFF) {
|
||||
synchronized (mMutex) {
|
||||
if (mCurrentConditionId != null) {
|
||||
if (DEBUG) Slog.d(TAG, "Zen mode off, forcing unsubscribe from "
|
||||
+ mCurrentConditionId);
|
||||
unsubscribeLocked(mCurrentConditionId);
|
||||
mCurrentConditionId = null;
|
||||
}
|
||||
}
|
||||
// ensure any manual condition is cleared
|
||||
setZenModeCondition(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConditionRecord {
|
||||
public final Uri id;
|
||||
public final ComponentName component;
|
||||
public Condition condition;
|
||||
public ManagedServiceInfo info;
|
||||
public boolean isAutomatic;
|
||||
public boolean isManual;
|
||||
|
||||
private ConditionRecord(Uri id, ComponentName component) {
|
||||
this.id = id;
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder("ConditionRecord[id=")
|
||||
.append(id).append(",component=").append(component);
|
||||
if (isAutomatic) sb.append(",automatic");
|
||||
if (isManual) sb.append(",manual");
|
||||
return sb.append(']').toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ abstract public class ManagedServices {
|
||||
|
||||
abstract protected IInterface asInterface(IBinder binder);
|
||||
|
||||
abstract protected void onServiceAdded(IInterface service);
|
||||
abstract protected void onServiceAdded(ManagedServiceInfo info);
|
||||
|
||||
protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
|
||||
|
||||
@@ -368,11 +368,12 @@ abstract public class ManagedServices {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder binder) {
|
||||
boolean added = false;
|
||||
ManagedServiceInfo info = null;
|
||||
synchronized (mMutex) {
|
||||
mServicesBinding.remove(servicesBindingTag);
|
||||
try {
|
||||
mService = asInterface(binder);
|
||||
ManagedServiceInfo info = newServiceInfo(mService, name,
|
||||
info = newServiceInfo(mService, name,
|
||||
userid, false /*isSystem*/, this, targetSdkVersion);
|
||||
binder.linkToDeath(info, 0);
|
||||
added = mServices.add(info);
|
||||
@@ -381,7 +382,7 @@ abstract public class ManagedServices {
|
||||
}
|
||||
}
|
||||
if (added) {
|
||||
onServiceAdded(mService);
|
||||
onServiceAdded(info);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1355,9 +1355,9 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestZenModeConditions(IConditionListener callback, boolean requested) {
|
||||
public void requestZenModeConditions(IConditionListener callback, int relevance) {
|
||||
enforceSystemOrSystemUI("INotificationManager.requestZenModeConditions");
|
||||
mConditionProviders.requestZenModeConditions(callback, requested);
|
||||
mConditionProviders.requestZenModeConditions(callback, relevance);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1366,6 +1366,18 @@ public class NotificationManagerService extends SystemService {
|
||||
mConditionProviders.setZenModeCondition(conditionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAutomaticZenModeConditions(Uri[] conditionIds) {
|
||||
enforceSystemOrSystemUI("INotificationManager.setAutomaticZenModeConditions");
|
||||
mConditionProviders.setAutomaticZenModeConditions(conditionIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Condition[] getAutomaticZenModeConditions() {
|
||||
enforceSystemOrSystemUI("INotificationManager.getAutomaticZenModeConditions");
|
||||
return mConditionProviders.getAutomaticZenModeConditions();
|
||||
}
|
||||
|
||||
private void enforceSystemOrSystemUI(String message) {
|
||||
if (isCallerSystem()) return;
|
||||
getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
|
||||
@@ -2320,8 +2332,8 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceAdded(IInterface service) {
|
||||
final INotificationListener listener = (INotificationListener) service;
|
||||
public void onServiceAdded(ManagedServiceInfo info) {
|
||||
final INotificationListener listener = (INotificationListener) info.service;
|
||||
final String[] keys = getActiveNotificationKeysFromListener(listener);
|
||||
try {
|
||||
listener.onListenerConnected(keys);
|
||||
|
||||
Reference in New Issue
Block a user