Merge "Add granular control over disabled effects." into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index 307e3f5..a5aadfa 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -34725,7 +34725,9 @@
method public static void requestRebind(android.content.ComponentName) throws android.os.RemoteException;
method public final void requestUnbind() throws android.os.RemoteException;
method public final void setNotificationsShown(java.lang.String[]);
+ field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
+ field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
diff --git a/api/system-current.txt b/api/system-current.txt
index f99381c..0902b53 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -37211,7 +37211,9 @@
method public final void setNotificationsShown(java.lang.String[]);
method public final void setOnNotificationPostedTrim(int);
method public void unregisterAsSystemService() throws android.os.RemoteException;
+ field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
+ field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
diff --git a/api/test-current.txt b/api/test-current.txt
index 86dcd5c..5ec3a5f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -34798,7 +34798,9 @@
method public static void requestRebind(android.content.ComponentName) throws android.os.RemoteException;
method public final void requestUnbind() throws android.os.RemoteException;
method public final void setNotificationsShown(java.lang.String[]);
+ field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
+ field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index a3f5224..e708b0a 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -123,6 +123,16 @@
* This does not change the interruption filter, only the effects. **/
public static final int HINT_HOST_DISABLE_EFFECTS = 1;
+ /** {@link #getCurrentListenerHints() Listener hints} constant - the primary device UI
+ * should disable notification sound, but not phone calls.
+ * This does not change the interruption filter, only the effects. **/
+ public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 1 << 1;
+
+ /** {@link #getCurrentListenerHints() Listener hints} constant - the primary device UI
+ * should disable phone call sounds, buyt not notification sound.
+ * This does not change the interruption filter, only the effects. **/
+ public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 1 << 2;
+
/**
* Whether notification suppressed by DND should not interruption visually when the screen is
* off.
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c855276..f20d0a1 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -33,6 +33,8 @@
import static android.service.notification.NotificationRankerService.REASON_UNAUTOBUNDLED;
import static android.service.notification.NotificationRankerService.REASON_USER_STOPPED;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
+import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
+import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
import static android.service.notification.NotificationListenerService.TRIM_FULL;
@@ -114,6 +116,7 @@
import android.util.AtomicFile;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.Xml;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -246,8 +249,9 @@
private String mSoundNotificationKey;
private String mVibrateNotificationKey;
- private final ArraySet<ManagedServiceInfo> mListenersDisablingEffects = new ArraySet<>();
- private ComponentName mEffectsSuppressor;
+ private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
+ new SparseArray<ArraySet<ManagedServiceInfo>>();
+ private List<ComponentName> mEffectsSuppressors = new ArrayList<ComponentName>();
private int mListenerHints; // right now, all hints are global
private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
@@ -1112,23 +1116,112 @@
}
private void updateListenerHintsLocked() {
- final int hints = mListenersDisablingEffects.isEmpty() ? 0 : HINT_HOST_DISABLE_EFFECTS;
+ final int hints = calculateHints();
if (hints == mListenerHints) return;
- ZenLog.traceListenerHintsChanged(mListenerHints, hints, mListenersDisablingEffects.size());
+ ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
mListenerHints = hints;
scheduleListenerHintsChanged(hints);
}
private void updateEffectsSuppressorLocked() {
- final ComponentName suppressor = !mListenersDisablingEffects.isEmpty()
- ? mListenersDisablingEffects.valueAt(0).component : null;
- if (Objects.equals(suppressor, mEffectsSuppressor)) return;
- ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressor, suppressor);
- mEffectsSuppressor = suppressor;
- mZenModeHelper.setEffectsSuppressed(suppressor != null);
+ final long updatedSuppressedEffects = calculateSuppressedEffects();
+ if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
+ final List<ComponentName> suppressors = getSuppressors();
+ ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
+ mEffectsSuppressors = suppressors;
+ mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
}
+ private ArrayList<ComponentName> getSuppressors() {
+ ArrayList<ComponentName> names = new ArrayList<ComponentName>();
+ for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
+ ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
+
+ for (ManagedServiceInfo info : serviceInfoList) {
+ names.add(info.component);
+ }
+ }
+
+ return names;
+ }
+
+ private boolean removeDisabledHints(ManagedServiceInfo info) {
+ return removeDisabledHints(info, 0);
+ }
+
+ private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
+ boolean removed = false;
+
+ for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
+ final int hint = mListenersDisablingEffects.keyAt(i);
+ final ArraySet<ManagedServiceInfo> listeners =
+ mListenersDisablingEffects.valueAt(i);
+
+ if (hints == 0 || (hint & hints) == hint) {
+ removed = removed || listeners.remove(info);
+ }
+ }
+
+ return removed;
+ }
+
+ private void addDisabledHints(ManagedServiceInfo info, int hints) {
+ if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
+ addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
+ }
+
+ if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
+ addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
+ }
+
+ if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
+ addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
+ }
+ }
+
+ private void addDisabledHint(ManagedServiceInfo info, int hint) {
+ if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
+ mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
+ }
+
+ ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
+ hintListeners.add(info);
+ }
+
+ private int calculateHints() {
+ int hints = 0;
+ for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
+ int hint = mListenersDisablingEffects.keyAt(i);
+ ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
+
+ if (!serviceInfoList.isEmpty()) {
+ hints |= hint;
+ }
+ }
+
+ return hints;
+ }
+
+ private long calculateSuppressedEffects() {
+ int hints = calculateHints();
+ long suppressedEffects = 0;
+
+ if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
+ suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
+ }
+
+ if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
+ suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
+ }
+
+ if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
+ suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
+ }
+
+ return suppressedEffects;
+ }
+
private void updateInterruptionFilterLocked() {
int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
if (interruptionFilter == mInterruptionFilter) return;
@@ -1651,11 +1744,14 @@
try {
synchronized (mNotificationList) {
final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
- final boolean disableEffects = (hints & HINT_HOST_DISABLE_EFFECTS) != 0;
+ final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
+ | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
+ | HINT_HOST_DISABLE_CALL_EFFECTS;
+ final boolean disableEffects = (hints & disableEffectsMask) != 0;
if (disableEffects) {
- mListenersDisablingEffects.add(info);
+ addDisabledHints(info, hints);
} else {
- mListenersDisablingEffects.remove(info);
+ removeDisabledHints(info, hints);
}
updateListenerHintsLocked();
updateEffectsSuppressorLocked();
@@ -1913,7 +2009,7 @@
@Override
public ComponentName getEffectsSuppressor() {
enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor");
- return mEffectsSuppressor;
+ return mEffectsSuppressors.get(0);
}
@Override
@@ -2273,9 +2369,19 @@
pw.print(" mListenersDisablingEffects: (");
N = mListenersDisablingEffects.size();
for (int i = 0; i < N; i++) {
- final ManagedServiceInfo listener = mListenersDisablingEffects.valueAt(i);
- if (i > 0) pw.print(',');
- pw.print(listener.component);
+ final int hint = mListenersDisablingEffects.keyAt(i);
+ if (i > 0) pw.print(';');
+ pw.print("hint[" + hint + "]:");
+
+ final ArraySet<ManagedServiceInfo> listeners =
+ mListenersDisablingEffects.valueAt(i);
+ final int listenerSize = listeners.size();
+
+ for (int j = 0; j < listenerSize; j++) {
+ if (i > 0) pw.print(',');
+ final ManagedServiceInfo listener = listeners.valueAt(i);
+ pw.print(listener.component);
+ }
}
pw.println(')');
pw.println("\n mRankerServicePackageName: " + mRankerServicePackageName);
@@ -3808,7 +3914,7 @@
@Override
protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
- if (mListenersDisablingEffects.remove(removed)) {
+ if (removeDisabledHints(removed)) {
updateListenerHintsLocked();
updateEffectsSuppressorLocked();
}
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index c45071b..207bdba 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -31,6 +31,7 @@
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
+import java.util.List;
public class ZenLog {
private static final String TAG = "ZenLog";
@@ -126,10 +127,11 @@
append(TYPE_DISABLE_EFFECTS, record.getKey() + "," + reason);
}
- public static void traceEffectsSuppressorChanged(ComponentName oldSuppressor,
- ComponentName newSuppressor) {
- append(TYPE_SUPPRESSOR_CHANGED, componentToString(oldSuppressor) + "->"
- + componentToString(newSuppressor));
+ public static void traceEffectsSuppressorChanged(List<ComponentName> oldSuppressors,
+ List<ComponentName> newSuppressors, long suppressedEffects) {
+ append(TYPE_SUPPRESSOR_CHANGED, "suppressed effects:" + suppressedEffects + ","
+ + componentListToString(oldSuppressors) + "->"
+ + componentListToString(newSuppressors));
}
public static void traceListenerHintsChanged(int oldHints, int newHints, int listenerCount) {
@@ -193,6 +195,19 @@
return component != null ? component.toShortString() : null;
}
+ private static String componentListToString(List<ComponentName> components) {
+ StringBuilder stringBuilder = new StringBuilder();
+
+ for (int i = 0; i < components.size(); ++i) {
+ if (i > 0) {
+ stringBuilder.append(", ");
+ }
+ stringBuilder.append(componentToString(components.get(i)));
+ }
+
+ return stringBuilder.toString();
+ }
+
private static void append(int type, String msg) {
synchronized(MSGS) {
TIMES[sNext] = System.currentTimeMillis();
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 5c5c8f8..eb49e9f 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -102,7 +102,12 @@
private ZenModeConfig mConfig;
private AudioManagerInternal mAudioManager;
private PackageManager mPm;
- private boolean mEffectsSuppressed;
+ private long mSuppressedEffects;
+
+ public static final long SUPPRESSED_EFFECT_NOTIFICATIONS = 1;
+ public static final long SUPPRESSED_EFFECT_CALLS = 1 << 1;
+ public static final long SUPPRESSED_EFFECT_ALL = SUPPRESSED_EFFECT_CALLS
+ | SUPPRESSED_EFFECT_NOTIFICATIONS;
public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
mContext = context;
@@ -228,12 +233,16 @@
}
}
- public void setEffectsSuppressed(boolean effectsSuppressed) {
- if (mEffectsSuppressed == effectsSuppressed) return;
- mEffectsSuppressed = effectsSuppressed;
+ public void setSuppressedEffects(long suppressedEffects) {
+ if (mSuppressedEffects == suppressedEffects) return;
+ mSuppressedEffects = suppressedEffects;
applyRestrictions();
}
+ public long getSuppressedEffects() {
+ return mSuppressedEffects;
+ }
+
public int getZenMode() {
return mZenMode;
}
@@ -484,7 +493,8 @@
synchronized (mConfig) {
dump(pw, prefix, "mConfig", mConfig);
}
- pw.print(prefix); pw.print("mEffectsSuppressed="); pw.println(mEffectsSuppressed);
+
+ pw.print(prefix); pw.print("mSuppressedEffects="); pw.println(mSuppressedEffects);
mFiltering.dump(pw, prefix);
mConditions.dump(pw, prefix);
}
@@ -708,9 +718,11 @@
final boolean zen = mZenMode != Global.ZEN_MODE_OFF;
// notification restrictions
- final boolean muteNotifications = mEffectsSuppressed;
+ final boolean muteNotifications =
+ (mSuppressedEffects & SUPPRESSED_EFFECT_NOTIFICATIONS) != 0;
// call restrictions
- final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers;
+ final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers
+ || (mSuppressedEffects & SUPPRESSED_EFFECT_CALLS) != 0;
// total silence restrictions
final boolean muteEverything = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;