diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index ad4027de4f609..b9172639e7c53 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -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(); } \ No newline at end of file diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java index 71e31663a76f6..dd8b34d5fed43 100644 --- a/core/java/android/service/notification/Condition.java +++ b/core/java/android/service/notification/Condition.java @@ -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; diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 925ddcfc79df8..846e292082946 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -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 conditionComponents = new ArrayList(); + final ArrayList conditionIds = new ArrayList(); 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; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java index 1bc97a075ab72..b09b4621ba4a1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java @@ -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 } diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java index 5567944169a39..d0745654b65ce 100644 --- a/services/core/java/com/android/server/notification/ConditionProviders.java +++ b/services/core/java/com/android/server/notification/ConditionProviders.java @@ -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 mListeners = new ArrayMap(); - private final ArrayMap mConditions - = new ArrayMap(); - - private Uri mCurrentConditionId; + private final ArrayList mRecords = new ArrayList(); 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 valid = new ArrayMap(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 ArraySet safeSet(T... items) { + final ArraySet rt = new ArraySet(); + 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 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 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(); + 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 newIds = new ArraySet(); + 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 automatic = new ArrayList(); + 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(); + } + } } diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index 0621f58a441bc..d34b09c3e55d9 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -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); } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 6e4eb565670f3..2e52983a3701a 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -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);