diff options
| -rw-r--r-- | api/current.txt | 2 | ||||
| -rw-r--r-- | api/system-current.txt | 2 | ||||
| -rw-r--r-- | api/test-current.txt | 2 | ||||
| -rw-r--r-- | core/java/android/service/notification/NotificationListenerService.java | 10 | ||||
| -rw-r--r-- | services/core/java/com/android/server/notification/NotificationManagerService.java | 142 | ||||
| -rw-r--r-- | services/core/java/com/android/server/notification/ZenLog.java | 23 | ||||
| -rw-r--r-- | services/core/java/com/android/server/notification/ZenModeHelper.java | 26 |
7 files changed, 178 insertions, 29 deletions
diff --git a/api/current.txt b/api/current.txt index 07a4f6d117d9..6097a271d966 100644 --- a/api/current.txt +++ b/api/current.txt @@ -34693,7 +34693,9 @@ package android.service.notification { 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 e1e73e93aacc..bbdc48cf6d0d 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -37176,7 +37176,9 @@ package android.service.notification { 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 09c55b927c60..2a42177effa8 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -34765,7 +34765,9 @@ package android.service.notification { 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 afdd1d43c35f..9a41edfd7467 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -117,6 +117,16 @@ public abstract class NotificationListenerService extends Service { * 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 124d7f1b9c97..19a18059e34e 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -32,6 +32,8 @@ import static android.service.notification.NotificationRankerService.REASON_PACK import static android.service.notification.NotificationRankerService.REASON_PROFILE_TURNED_OFF; 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.ArraySet; 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; @@ -248,8 +251,9 @@ public class NotificationManagerService extends SystemService { 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; @@ -1119,23 +1123,112 @@ public class NotificationManagerService extends SystemService { } 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; @@ -1652,11 +1745,14 @@ public class NotificationManagerService extends SystemService { 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(); @@ -1914,7 +2010,7 @@ public class NotificationManagerService extends SystemService { @Override public ComponentName getEffectsSuppressor() { enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor"); - return mEffectsSuppressor; + return mEffectsSuppressors.get(0); } @Override @@ -2176,9 +2272,19 @@ public class NotificationManagerService extends SystemService { 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); @@ -3690,7 +3796,7 @@ public class NotificationManagerService extends SystemService { @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 c45071b5080b..207bdba47ff6 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 android.util.Slog; 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 @@ public class ZenLog { 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 @@ public class ZenLog { 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 5c5c8f854105..eb49e9f80550 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 @@ public class ZenModeHelper { 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 class ZenModeHelper { } } - 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 @@ public class ZenModeHelper { 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 @@ public class ZenModeHelper { 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; |