1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.app;
18
19import android.annotation.IntDef;
20import android.annotation.NonNull;
21import android.annotation.SdkConstant;
22import android.app.Notification.Builder;
23import android.content.ComponentName;
24import android.content.Context;
25import android.content.pm.ParceledListSlice;
26import android.graphics.drawable.Icon;
27import android.net.Uri;
28import android.os.Build;
29import android.os.Bundle;
30import android.os.Handler;
31import android.os.IBinder;
32import android.os.Parcel;
33import android.os.Parcelable;
34import android.os.RemoteException;
35import android.os.ServiceManager;
36import android.os.StrictMode;
37import android.os.UserHandle;
38import android.provider.Settings.Global;
39import android.service.notification.NotificationListenerService.Ranking;
40import android.service.notification.StatusBarNotification;
41import android.service.notification.ZenModeConfig;
42import android.util.ArraySet;
43import android.util.Log;
44
45import java.lang.annotation.Retention;
46import java.lang.annotation.RetentionPolicy;
47import java.util.HashMap;
48import java.util.List;
49import java.util.Map;
50import java.util.Objects;
51
52/**
53 * Class to notify the user of events that happen.  This is how you tell
54 * the user that something has happened in the background. {@more}
55 *
56 * Notifications can take different forms:
57 * <ul>
58 *      <li>A persistent icon that goes in the status bar and is accessible
59 *          through the launcher, (when the user selects it, a designated Intent
60 *          can be launched),</li>
61 *      <li>Turning on or flashing LEDs on the device, or</li>
62 *      <li>Alerting the user by flashing the backlight, playing a sound,
63 *          or vibrating.</li>
64 * </ul>
65 *
66 * <p>
67 * Each of the notify methods takes an int id parameter and optionally a
68 * {@link String} tag parameter, which may be {@code null}.  These parameters
69 * are used to form a pair (tag, id), or ({@code null}, id) if tag is
70 * unspecified.  This pair identifies this notification from your app to the
71 * system, so that pair should be unique within your app.  If you call one
72 * of the notify methods with a (tag, id) pair that is currently active and
73 * a new set of notification parameters, it will be updated.  For example,
74 * if you pass a new status bar icon, the old icon in the status bar will
75 * be replaced with the new one.  This is also the same tag and id you pass
76 * to the {@link #cancel(int)} or {@link #cancel(String, int)} method to clear
77 * this notification.
78 *
79 * <p>
80 * You do not instantiate this class directly; instead, retrieve it through
81 * {@link android.content.Context#getSystemService}.
82 *
83 * <div class="special reference">
84 * <h3>Developer Guides</h3>
85 * <p>For a guide to creating notifications, read the
86 * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Status Bar Notifications</a>
87 * developer guide.</p>
88 * </div>
89 *
90 * @see android.app.Notification
91 * @see android.content.Context#getSystemService
92 */
93public class NotificationManager
94{
95    private static String TAG = "NotificationManager";
96    private static boolean localLOGV = false;
97
98    /**
99     * Intent that is broadcast when the state of {@link #getEffectsSuppressor()} changes.
100     * This broadcast is only sent to registered receivers.
101     *
102     * @hide
103     */
104    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
105    public static final String ACTION_EFFECTS_SUPPRESSOR_CHANGED
106            = "android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED";
107
108    /**
109     * Intent that is broadcast when the state of {@link #isNotificationPolicyAccessGranted()}
110     * changes.
111     *
112     * This broadcast is only sent to registered receivers, and only to the apps that have changed.
113     */
114    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
115    public static final String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED
116            = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
117
118    /**
119     * Intent that is broadcast when the state of getNotificationPolicy() changes.
120     * This broadcast is only sent to registered receivers.
121     */
122    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
123    public static final String ACTION_NOTIFICATION_POLICY_CHANGED
124            = "android.app.action.NOTIFICATION_POLICY_CHANGED";
125
126    /**
127     * Intent that is broadcast when the state of getCurrentInterruptionFilter() changes.
128     * This broadcast is only sent to registered receivers.
129     */
130    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
131    public static final String ACTION_INTERRUPTION_FILTER_CHANGED
132            = "android.app.action.INTERRUPTION_FILTER_CHANGED";
133
134    /**
135     * Intent that is broadcast when the state of getCurrentInterruptionFilter() changes.
136     * @hide
137     */
138    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
139    public static final String ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL
140            = "android.app.action.INTERRUPTION_FILTER_CHANGED_INTERNAL";
141
142    /** @hide */
143    @IntDef({INTERRUPTION_FILTER_NONE, INTERRUPTION_FILTER_PRIORITY, INTERRUPTION_FILTER_ALARMS,
144            INTERRUPTION_FILTER_ALL, INTERRUPTION_FILTER_UNKNOWN})
145    @Retention(RetentionPolicy.SOURCE)
146    public @interface InterruptionFilter {}
147
148    /**
149     * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
150     *     Normal interruption filter - no notifications are suppressed.
151     */
152    public static final int INTERRUPTION_FILTER_ALL = 1;
153
154    /**
155     * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
156     *     Priority interruption filter - all notifications are suppressed except those that match
157     *     the priority criteria. Some audio streams are muted. See
158     *     {@link Policy#priorityCallSenders}, {@link Policy#priorityCategories},
159     *     {@link Policy#priorityMessageSenders} to define or query this criteria. Users can
160     *     additionally specify packages that can bypass this interruption filter.
161     */
162    public static final int INTERRUPTION_FILTER_PRIORITY = 2;
163
164    /**
165     * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
166     *     No interruptions filter - all notifications are suppressed and all audio streams (except
167     *     those used for phone calls) and vibrations are muted.
168     */
169    public static final int INTERRUPTION_FILTER_NONE = 3;
170
171    /**
172     * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
173     *     Alarms only interruption filter - all notifications except those of category
174     *     {@link Notification#CATEGORY_ALARM} are suppressed. Some audio streams are muted.
175     */
176    public static final int INTERRUPTION_FILTER_ALARMS = 4;
177
178    /** {@link #getCurrentInterruptionFilter() Interruption filter} constant - returned when
179     * the value is unavailable for any reason.
180     */
181    public static final int INTERRUPTION_FILTER_UNKNOWN = 0;
182
183    /** @hide */
184    @IntDef({VISIBILITY_NO_OVERRIDE, IMPORTANCE_UNSPECIFIED, IMPORTANCE_NONE,
185            IMPORTANCE_MIN, IMPORTANCE_LOW, IMPORTANCE_DEFAULT, IMPORTANCE_HIGH,
186            IMPORTANCE_MAX})
187    @Retention(RetentionPolicy.SOURCE)
188    public @interface Importance {}
189
190    /** Value signifying that the user has not expressed a per-app visibility override value.
191     * @hide */
192    public static final int VISIBILITY_NO_OVERRIDE = -1000;
193    /**
194     * Value signifying that the user has not expressed an importance.
195     *
196     * This value is for persisting preferences, and should never be associated with
197     * an actual notification.
198     */
199    public static final int IMPORTANCE_UNSPECIFIED = -1000;
200
201    /**
202     * A notification with no importance: shows nowhere, is blocked.
203     */
204    public static final int IMPORTANCE_NONE = 0;
205
206    /**
207     * Min notification importance: only shows in the shade, below the fold.
208     */
209    public static final int IMPORTANCE_MIN = 1;
210
211    /**
212     * Low notification importance: shows everywhere, but is not intrusive.
213     */
214    public static final int IMPORTANCE_LOW = 2;
215
216    /**
217     * Default notification importance: shows everywhere, allowed to makes noise,
218     * but does not visually intrude.
219     */
220    public static final int IMPORTANCE_DEFAULT = 3;
221
222    /**
223     * Higher notification importance: shows everywhere, allowed to makes noise and peek.
224     */
225    public static final int IMPORTANCE_HIGH = 4;
226
227    /**
228     * Highest notification importance: shows everywhere, allowed to makes noise, peek, and
229     * use full screen intents.
230     */
231    public static final int IMPORTANCE_MAX = 5;
232
233    private static INotificationManager sService;
234
235    /** @hide */
236    static public INotificationManager getService()
237    {
238        if (sService != null) {
239            return sService;
240        }
241        IBinder b = ServiceManager.getService("notification");
242        sService = INotificationManager.Stub.asInterface(b);
243        return sService;
244    }
245
246    /*package*/ NotificationManager(Context context, Handler handler)
247    {
248        mContext = context;
249    }
250
251    /** {@hide} */
252    public static NotificationManager from(Context context) {
253        return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
254    }
255
256    /**
257     * Post a notification to be shown in the status bar. If a notification with
258     * the same id has already been posted by your application and has not yet been canceled, it
259     * will be replaced by the updated information.
260     *
261     * @param id An identifier for this notification unique within your
262     *        application.
263     * @param notification A {@link Notification} object describing what to show the user. Must not
264     *        be null.
265     */
266    public void notify(int id, Notification notification)
267    {
268        notify(null, id, notification);
269    }
270
271    /**
272     * Post a notification to be shown in the status bar. If a notification with
273     * the same tag and id has already been posted by your application and has not yet been
274     * canceled, it will be replaced by the updated information.
275     *
276     * @param tag A string identifier for this notification.  May be {@code null}.
277     * @param id An identifier for this notification.  The pair (tag, id) must be unique
278     *        within your application.
279     * @param notification A {@link Notification} object describing what to
280     *        show the user. Must not be null.
281     */
282    public void notify(String tag, int id, Notification notification)
283    {
284        notifyAsUser(tag, id, notification, new UserHandle(UserHandle.myUserId()));
285    }
286
287    /**
288     * @hide
289     */
290    public void notifyAsUser(String tag, int id, Notification notification, UserHandle user)
291    {
292        int[] idOut = new int[1];
293        INotificationManager service = getService();
294        String pkg = mContext.getPackageName();
295        // Fix the notification as best we can.
296        Notification.addFieldsFromContext(mContext, notification);
297        if (notification.sound != null) {
298            notification.sound = notification.sound.getCanonicalUri();
299            if (StrictMode.vmFileUriExposureEnabled()) {
300                notification.sound.checkFileUriExposed("Notification.sound");
301            }
302        }
303        fixLegacySmallIcon(notification, pkg);
304        if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
305            if (notification.getSmallIcon() == null) {
306                throw new IllegalArgumentException("Invalid notification (no valid small icon): "
307                        + notification);
308            }
309        }
310        if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
311        final Notification copy = Builder.maybeCloneStrippedForDelivery(notification);
312        try {
313            service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
314                    copy, idOut, user.getIdentifier());
315            if (localLOGV && id != idOut[0]) {
316                Log.v(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
317            }
318        } catch (RemoteException e) {
319            throw e.rethrowFromSystemServer();
320        }
321    }
322
323    private void fixLegacySmallIcon(Notification n, String pkg) {
324        if (n.getSmallIcon() == null && n.icon != 0) {
325            n.setSmallIcon(Icon.createWithResource(pkg, n.icon));
326        }
327    }
328
329    /**
330     * Cancel a previously shown notification.  If it's transient, the view
331     * will be hidden.  If it's persistent, it will be removed from the status
332     * bar.
333     */
334    public void cancel(int id)
335    {
336        cancel(null, id);
337    }
338
339    /**
340     * Cancel a previously shown notification.  If it's transient, the view
341     * will be hidden.  If it's persistent, it will be removed from the status
342     * bar.
343     */
344    public void cancel(String tag, int id)
345    {
346        cancelAsUser(tag, id, new UserHandle(UserHandle.myUserId()));
347    }
348
349    /**
350     * @hide
351     */
352    public void cancelAsUser(String tag, int id, UserHandle user)
353    {
354        INotificationManager service = getService();
355        String pkg = mContext.getPackageName();
356        if (localLOGV) Log.v(TAG, pkg + ": cancel(" + id + ")");
357        try {
358            service.cancelNotificationWithTag(pkg, tag, id, user.getIdentifier());
359        } catch (RemoteException e) {
360            throw e.rethrowFromSystemServer();
361        }
362    }
363
364    /**
365     * Cancel all previously shown notifications. See {@link #cancel} for the
366     * detailed behavior.
367     */
368    public void cancelAll()
369    {
370        INotificationManager service = getService();
371        String pkg = mContext.getPackageName();
372        if (localLOGV) Log.v(TAG, pkg + ": cancelAll()");
373        try {
374            service.cancelAllNotifications(pkg, UserHandle.myUserId());
375        } catch (RemoteException e) {
376            throw e.rethrowFromSystemServer();
377        }
378    }
379
380    /**
381     * @hide
382     */
383    public ComponentName getEffectsSuppressor() {
384        INotificationManager service = getService();
385        try {
386            return service.getEffectsSuppressor();
387        } catch (RemoteException e) {
388            throw e.rethrowFromSystemServer();
389        }
390    }
391
392    /**
393     * @hide
394     */
395    public boolean matchesCallFilter(Bundle extras) {
396        INotificationManager service = getService();
397        try {
398            return service.matchesCallFilter(extras);
399        } catch (RemoteException e) {
400            throw e.rethrowFromSystemServer();
401        }
402    }
403
404    /**
405     * @hide
406     */
407    public boolean isSystemConditionProviderEnabled(String path) {
408        INotificationManager service = getService();
409        try {
410            return service.isSystemConditionProviderEnabled(path);
411        } catch (RemoteException e) {
412            throw e.rethrowFromSystemServer();
413        }
414    }
415
416    /**
417     * @hide
418     */
419    public void setZenMode(int mode, Uri conditionId, String reason) {
420        INotificationManager service = getService();
421        try {
422            service.setZenMode(mode, conditionId, reason);
423        } catch (RemoteException e) {
424            throw e.rethrowFromSystemServer();
425        }
426    }
427
428    /**
429     * @hide
430     */
431    public int getZenMode() {
432        INotificationManager service = getService();
433        try {
434            return service.getZenMode();
435        } catch (RemoteException e) {
436            throw e.rethrowFromSystemServer();
437        }
438    }
439
440    /**
441     * @hide
442     */
443    public ZenModeConfig getZenModeConfig() {
444        INotificationManager service = getService();
445        try {
446            return service.getZenModeConfig();
447        } catch (RemoteException e) {
448            throw e.rethrowFromSystemServer();
449        }
450    }
451
452    /**
453     * @hide
454     */
455    public int getRuleInstanceCount(ComponentName owner) {
456        INotificationManager service = getService();
457        try {
458            return service.getRuleInstanceCount(owner);
459        } catch (RemoteException e) {
460            throw e.rethrowFromSystemServer();
461        }
462    }
463
464    /**
465     * Returns AutomaticZenRules owned by the caller.
466     *
467     * <p>
468     * Throws a SecurityException if policy access is granted to this package.
469     * See {@link #isNotificationPolicyAccessGranted}.
470     */
471    public Map<String, AutomaticZenRule> getAutomaticZenRules() {
472        INotificationManager service = getService();
473        try {
474            List<ZenModeConfig.ZenRule> rules = service.getZenRules();
475            Map<String, AutomaticZenRule> ruleMap = new HashMap<>();
476            for (ZenModeConfig.ZenRule rule : rules) {
477                ruleMap.put(rule.id, new AutomaticZenRule(rule.name, rule.component,
478                        rule.conditionId, zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
479                        rule.creationTime));
480            }
481            return ruleMap;
482        } catch (RemoteException e) {
483            throw e.rethrowFromSystemServer();
484        }
485    }
486
487    /**
488     * Returns the AutomaticZenRule with the given id, if it exists and the caller has access.
489     *
490     * <p>
491     * Throws a SecurityException if policy access is granted to this package.
492     * See {@link #isNotificationPolicyAccessGranted}.
493     *
494     * <p>
495     * Returns null if there are no zen rules that match the given id, or if the calling package
496     * doesn't own the matching rule. See {@link AutomaticZenRule#getOwner}.
497     */
498    public AutomaticZenRule getAutomaticZenRule(String id) {
499        INotificationManager service = getService();
500        try {
501            return service.getAutomaticZenRule(id);
502        } catch (RemoteException e) {
503            throw e.rethrowFromSystemServer();
504        }
505    }
506
507    /**
508     * Creates the given zen rule.
509     *
510     * <p>
511     * Throws a SecurityException if policy access is granted to this package.
512     * See {@link #isNotificationPolicyAccessGranted}.
513     *
514     * @param automaticZenRule the rule to create.
515     * @return The id of the newly created rule; null if the rule could not be created.
516     */
517    public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) {
518        INotificationManager service = getService();
519        try {
520            return service.addAutomaticZenRule(automaticZenRule);
521        } catch (RemoteException e) {
522            throw e.rethrowFromSystemServer();
523        }
524    }
525
526    /**
527     * Updates the given zen rule.
528     *
529     * <p>
530     * Throws a SecurityException if policy access is granted to this package.
531     * See {@link #isNotificationPolicyAccessGranted}.
532     *
533     * <p>
534     * Callers can only update rules that they own. See {@link AutomaticZenRule#getOwner}.
535     * @param id The id of the rule to update
536     * @param automaticZenRule the rule to update.
537     * @return Whether the rule was successfully updated.
538     */
539    public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule) {
540        INotificationManager service = getService();
541        try {
542            return service.updateAutomaticZenRule(id, automaticZenRule);
543        } catch (RemoteException e) {
544            throw e.rethrowFromSystemServer();
545        }
546    }
547
548    /**
549     * Deletes the automatic zen rule with the given id.
550     *
551     * <p>
552     * Throws a SecurityException if policy access is granted to this package.
553     * See {@link #isNotificationPolicyAccessGranted}.
554     *
555     * <p>
556     * Callers can only delete rules that they own. See {@link AutomaticZenRule#getOwner}.
557     * @param id the id of the rule to delete.
558     * @return Whether the rule was successfully deleted.
559     */
560    public boolean removeAutomaticZenRule(String id) {
561        INotificationManager service = getService();
562        try {
563            return service.removeAutomaticZenRule(id);
564        } catch (RemoteException e) {
565            throw e.rethrowFromSystemServer();
566        }
567    }
568
569    /**
570     * Deletes all automatic zen rules owned by the given package.
571     *
572     * @hide
573     */
574    public boolean removeAutomaticZenRules(String packageName) {
575        INotificationManager service = getService();
576        try {
577            return service.removeAutomaticZenRules(packageName);
578        } catch (RemoteException e) {
579            throw e.rethrowFromSystemServer();
580        }
581    }
582
583    /**
584     * Returns the user specified importance for notifications from the calling package.
585     *
586     * @return An importance level, such as {@link #IMPORTANCE_DEFAULT}.
587     */
588    public @Importance int getImportance() {
589        INotificationManager service = getService();
590        try {
591            return service.getPackageImportance(mContext.getPackageName());
592        } catch (RemoteException e) {
593            throw e.rethrowFromSystemServer();
594        }
595    }
596
597    /**
598     * Returns whether notifications from the calling package are blocked.
599     */
600    public boolean areNotificationsEnabled() {
601        INotificationManager service = getService();
602        try {
603            return service.areNotificationsEnabled(mContext.getPackageName());
604        } catch (RemoteException e) {
605            throw e.rethrowFromSystemServer();
606        }
607    }
608
609    /**
610     * Checks the ability to read/modify notification policy for the calling package.
611     *
612     * <p>
613     * Returns true if the calling package can read/modify notification policy.
614     *
615     * <p>
616     * Request policy access by sending the user to the activity that matches the system intent
617     * action {@link android.provider.Settings#ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS}.
618     *
619     * <p>
620     * Use {@link #ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED} to listen for
621     * user grant or denial of this access.
622     */
623    public boolean isNotificationPolicyAccessGranted() {
624        INotificationManager service = getService();
625        try {
626            return service.isNotificationPolicyAccessGranted(mContext.getOpPackageName());
627        } catch (RemoteException e) {
628            throw e.rethrowFromSystemServer();
629        }
630    }
631
632    /** @hide */
633    public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {
634        INotificationManager service = getService();
635        try {
636            return service.isNotificationPolicyAccessGrantedForPackage(pkg);
637        } catch (RemoteException e) {
638            throw e.rethrowFromSystemServer();
639        }
640    }
641
642    /**
643     * Gets the current notification policy.
644     *
645     * <p>
646     * Only available if policy access is granted to this package.
647     * See {@link #isNotificationPolicyAccessGranted}.
648     */
649    public Policy getNotificationPolicy() {
650        INotificationManager service = getService();
651        try {
652            return service.getNotificationPolicy(mContext.getOpPackageName());
653        } catch (RemoteException e) {
654            throw e.rethrowFromSystemServer();
655        }
656    }
657
658    /**
659     * Sets the current notification policy.
660     *
661     * <p>
662     * Only available if policy access is granted to this package.
663     * See {@link #isNotificationPolicyAccessGranted}.
664     *
665     * @param policy The new desired policy.
666     */
667    public void setNotificationPolicy(@NonNull Policy policy) {
668        checkRequired("policy", policy);
669        INotificationManager service = getService();
670        try {
671            service.setNotificationPolicy(mContext.getOpPackageName(), policy);
672        } catch (RemoteException e) {
673            throw e.rethrowFromSystemServer();
674        }
675    }
676
677    /** @hide */
678    public void setNotificationPolicyAccessGranted(String pkg, boolean granted) {
679        INotificationManager service = getService();
680        try {
681            service.setNotificationPolicyAccessGranted(pkg, granted);
682        } catch (RemoteException e) {
683            throw e.rethrowFromSystemServer();
684        }
685    }
686
687    /** @hide */
688    public ArraySet<String> getPackagesRequestingNotificationPolicyAccess() {
689        INotificationManager service = getService();
690        try {
691            final String[] pkgs = service.getPackagesRequestingNotificationPolicyAccess();
692            if (pkgs != null && pkgs.length > 0) {
693                final ArraySet<String> rt = new ArraySet<>(pkgs.length);
694                for (int i = 0; i < pkgs.length; i++) {
695                    rt.add(pkgs[i]);
696                }
697                return rt;
698            }
699        } catch (RemoteException e) {
700            throw e.rethrowFromSystemServer();
701        }
702        return new ArraySet<>();
703    }
704
705    private Context mContext;
706
707    private static void checkRequired(String name, Object value) {
708        if (value == null) {
709            throw new IllegalArgumentException(name + " is required");
710        }
711    }
712
713    /**
714     * Notification policy configuration.  Represents user-preferences for notification
715     * filtering.
716     */
717    public static class Policy implements android.os.Parcelable {
718        /** Reminder notifications are prioritized. */
719        public static final int PRIORITY_CATEGORY_REMINDERS = 1 << 0;
720        /** Event notifications are prioritized. */
721        public static final int PRIORITY_CATEGORY_EVENTS = 1 << 1;
722        /** Message notifications are prioritized. */
723        public static final int PRIORITY_CATEGORY_MESSAGES = 1 << 2;
724        /** Calls are prioritized. */
725        public static final int PRIORITY_CATEGORY_CALLS = 1 << 3;
726        /** Calls from repeat callers are prioritized. */
727        public static final int PRIORITY_CATEGORY_REPEAT_CALLERS = 1 << 4;
728
729        private static final int[] ALL_PRIORITY_CATEGORIES = {
730            PRIORITY_CATEGORY_REMINDERS,
731            PRIORITY_CATEGORY_EVENTS,
732            PRIORITY_CATEGORY_MESSAGES,
733            PRIORITY_CATEGORY_CALLS,
734            PRIORITY_CATEGORY_REPEAT_CALLERS,
735        };
736
737        /** Any sender is prioritized. */
738        public static final int PRIORITY_SENDERS_ANY = 0;
739        /** Saved contacts are prioritized. */
740        public static final int PRIORITY_SENDERS_CONTACTS = 1;
741        /** Only starred contacts are prioritized. */
742        public static final int PRIORITY_SENDERS_STARRED = 2;
743
744        /** Notification categories to prioritize. Bitmask of PRIORITY_CATEGORY_* constants. */
745        public final int priorityCategories;
746
747        /** Notification senders to prioritize for calls. One of:
748         * PRIORITY_SENDERS_ANY, PRIORITY_SENDERS_CONTACTS, PRIORITY_SENDERS_STARRED */
749        public final int priorityCallSenders;
750
751        /** Notification senders to prioritize for messages. One of:
752         * PRIORITY_SENDERS_ANY, PRIORITY_SENDERS_CONTACTS, PRIORITY_SENDERS_STARRED */
753        public final int priorityMessageSenders;
754
755        /**
756         * @hide
757         */
758        public static final int SUPPRESSED_EFFECTS_UNSET = -1;
759        /**
760         * Whether notifications suppressed by DND should not interrupt visually (e.g. with
761         * notification lights or by turning the screen on) when the screen is off.
762         */
763        public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1 << 0;
764        /**
765         * Whether notifications suppressed by DND should not interrupt visually when the screen
766         * is on (e.g. by peeking onto the screen).
767         */
768        public static final int SUPPRESSED_EFFECT_SCREEN_ON = 1 << 1;
769
770        private static final int[] ALL_SUPPRESSED_EFFECTS = {
771                SUPPRESSED_EFFECT_SCREEN_OFF,
772                SUPPRESSED_EFFECT_SCREEN_ON,
773        };
774
775        /**
776         * Visual effects to suppress for a notification that is filtered by Do Not Disturb mode.
777         * Bitmask of SUPPRESSED_EFFECT_* constants.
778         */
779        public final int suppressedVisualEffects;
780
781        /**
782         * Constructs a policy for Do Not Disturb priority mode behavior.
783         *
784         * @param priorityCategories bitmask of categories of notifications that can bypass DND.
785         * @param priorityCallSenders which callers can bypass DND.
786         * @param priorityMessageSenders which message senders can bypass DND.
787         */
788        public Policy(int priorityCategories, int priorityCallSenders, int priorityMessageSenders) {
789            this(priorityCategories, priorityCallSenders, priorityMessageSenders,
790                    SUPPRESSED_EFFECTS_UNSET);
791        }
792
793        /**
794         * Constructs a policy for Do Not Disturb priority mode behavior.
795         *
796         * @param priorityCategories bitmask of categories of notifications that can bypass DND.
797         * @param priorityCallSenders which callers can bypass DND.
798         * @param priorityMessageSenders which message senders can bypass DND.
799         * @param suppressedVisualEffects which visual interruptions should be suppressed from
800         *                                notifications that are filtered by DND.
801         */
802        public Policy(int priorityCategories, int priorityCallSenders, int priorityMessageSenders,
803                int suppressedVisualEffects) {
804            this.priorityCategories = priorityCategories;
805            this.priorityCallSenders = priorityCallSenders;
806            this.priorityMessageSenders = priorityMessageSenders;
807            this.suppressedVisualEffects = suppressedVisualEffects;
808        }
809
810        /** @hide */
811        public Policy(Parcel source) {
812            this(source.readInt(), source.readInt(), source.readInt(), source.readInt());
813        }
814
815        @Override
816        public void writeToParcel(Parcel dest, int flags) {
817            dest.writeInt(priorityCategories);
818            dest.writeInt(priorityCallSenders);
819            dest.writeInt(priorityMessageSenders);
820            dest.writeInt(suppressedVisualEffects);
821        }
822
823        @Override
824        public int describeContents() {
825            return 0;
826        }
827
828        @Override
829        public int hashCode() {
830            return Objects.hash(priorityCategories, priorityCallSenders, priorityMessageSenders,
831                    suppressedVisualEffects);
832        }
833
834        @Override
835        public boolean equals(Object o) {
836            if (!(o instanceof Policy)) return false;
837            if (o == this) return true;
838            final Policy other = (Policy) o;
839            return other.priorityCategories == priorityCategories
840                    && other.priorityCallSenders == priorityCallSenders
841                    && other.priorityMessageSenders == priorityMessageSenders
842                    && other.suppressedVisualEffects == suppressedVisualEffects;
843        }
844
845        @Override
846        public String toString() {
847            return "NotificationManager.Policy["
848                    + "priorityCategories=" + priorityCategoriesToString(priorityCategories)
849                    + ",priorityCallSenders=" + prioritySendersToString(priorityCallSenders)
850                    + ",priorityMessageSenders=" + prioritySendersToString(priorityMessageSenders)
851                    + ",suppressedVisualEffects="
852                    + suppressedEffectsToString(suppressedVisualEffects)
853                    + "]";
854        }
855
856        public static String suppressedEffectsToString(int effects) {
857            if (effects <= 0) return "";
858            final StringBuilder sb = new StringBuilder();
859            for (int i = 0; i < ALL_SUPPRESSED_EFFECTS.length; i++) {
860                final int effect = ALL_SUPPRESSED_EFFECTS[i];
861                if ((effects & effect) != 0) {
862                    if (sb.length() > 0) sb.append(',');
863                    sb.append(effectToString(effect));
864                }
865                effects &= ~effect;
866            }
867            if (effects != 0) {
868                if (sb.length() > 0) sb.append(',');
869                sb.append("UNKNOWN_").append(effects);
870            }
871            return sb.toString();
872        }
873
874        public static String priorityCategoriesToString(int priorityCategories) {
875            if (priorityCategories == 0) return "";
876            final StringBuilder sb = new StringBuilder();
877            for (int i = 0; i < ALL_PRIORITY_CATEGORIES.length; i++) {
878                final int priorityCategory = ALL_PRIORITY_CATEGORIES[i];
879                if ((priorityCategories & priorityCategory) != 0) {
880                    if (sb.length() > 0) sb.append(',');
881                    sb.append(priorityCategoryToString(priorityCategory));
882                }
883                priorityCategories &= ~priorityCategory;
884            }
885            if (priorityCategories != 0) {
886                if (sb.length() > 0) sb.append(',');
887                sb.append("PRIORITY_CATEGORY_UNKNOWN_").append(priorityCategories);
888            }
889            return sb.toString();
890        }
891
892        private static String effectToString(int effect) {
893            switch (effect) {
894                case SUPPRESSED_EFFECT_SCREEN_OFF: return "SUPPRESSED_EFFECT_SCREEN_OFF";
895                case SUPPRESSED_EFFECT_SCREEN_ON: return "SUPPRESSED_EFFECT_SCREEN_ON";
896                case SUPPRESSED_EFFECTS_UNSET: return "SUPPRESSED_EFFECTS_UNSET";
897                default: return "UNKNOWN_" + effect;
898            }
899        }
900
901        private static String priorityCategoryToString(int priorityCategory) {
902            switch (priorityCategory) {
903                case PRIORITY_CATEGORY_REMINDERS: return "PRIORITY_CATEGORY_REMINDERS";
904                case PRIORITY_CATEGORY_EVENTS: return "PRIORITY_CATEGORY_EVENTS";
905                case PRIORITY_CATEGORY_MESSAGES: return "PRIORITY_CATEGORY_MESSAGES";
906                case PRIORITY_CATEGORY_CALLS: return "PRIORITY_CATEGORY_CALLS";
907                case PRIORITY_CATEGORY_REPEAT_CALLERS: return "PRIORITY_CATEGORY_REPEAT_CALLERS";
908                default: return "PRIORITY_CATEGORY_UNKNOWN_" + priorityCategory;
909            }
910        }
911
912        public static String prioritySendersToString(int prioritySenders) {
913            switch (prioritySenders) {
914                case PRIORITY_SENDERS_ANY: return "PRIORITY_SENDERS_ANY";
915                case PRIORITY_SENDERS_CONTACTS: return "PRIORITY_SENDERS_CONTACTS";
916                case PRIORITY_SENDERS_STARRED: return "PRIORITY_SENDERS_STARRED";
917                default: return "PRIORITY_SENDERS_UNKNOWN_" + prioritySenders;
918            }
919        }
920
921        public static final Parcelable.Creator<Policy> CREATOR = new Parcelable.Creator<Policy>() {
922            @Override
923            public Policy createFromParcel(Parcel in) {
924                return new Policy(in);
925            }
926
927            @Override
928            public Policy[] newArray(int size) {
929                return new Policy[size];
930            }
931        };
932    }
933
934    /**
935     * Recover a list of active notifications: ones that have been posted by the calling app that
936     * have not yet been dismissed by the user or {@link #cancel(String, int)}ed by the app.
937     *
938     * Each notification is embedded in a {@link StatusBarNotification} object, including the
939     * original <code>tag</code> and <code>id</code> supplied to
940     * {@link #notify(String, int, Notification) notify()}
941     * (via {@link StatusBarNotification#getTag() getTag()} and
942     * {@link StatusBarNotification#getId() getId()}) as well as a copy of the original
943     * {@link Notification} object (via {@link StatusBarNotification#getNotification()}).
944     *
945     * @return An array of {@link StatusBarNotification}.
946     */
947    public StatusBarNotification[] getActiveNotifications() {
948        final INotificationManager service = getService();
949        final String pkg = mContext.getPackageName();
950        try {
951            final ParceledListSlice<StatusBarNotification> parceledList
952                    = service.getAppActiveNotifications(pkg, UserHandle.myUserId());
953            final List<StatusBarNotification> list = parceledList.getList();
954            return list.toArray(new StatusBarNotification[list.size()]);
955        } catch (RemoteException e) {
956            throw e.rethrowFromSystemServer();
957        }
958    }
959
960    /**
961     * Gets the current notification interruption filter.
962     *
963     * <p>
964     * The interruption filter defines which notifications are allowed to interrupt the user
965     * (e.g. via sound &amp; vibration) and is applied globally.
966     * @return One of the INTERRUPTION_FILTER_ constants, or INTERRUPTION_FILTER_UNKNOWN when
967     * unavailable.
968     */
969    public final @InterruptionFilter int getCurrentInterruptionFilter() {
970        final INotificationManager service = getService();
971        try {
972            return zenModeToInterruptionFilter(service.getZenMode());
973        } catch (RemoteException e) {
974            throw e.rethrowFromSystemServer();
975        }
976    }
977
978    /**
979     * Sets the current notification interruption filter.
980     *
981     * <p>
982     * The interruption filter defines which notifications are allowed to interrupt the user
983     * (e.g. via sound &amp; vibration) and is applied globally.
984     * @return One of the INTERRUPTION_FILTER_ constants, or INTERRUPTION_FILTER_UNKNOWN when
985     * unavailable.
986     *
987     * <p>
988     * Only available if policy access is granted to this package.
989     * See {@link #isNotificationPolicyAccessGranted}.
990     */
991    public final void setInterruptionFilter(int interruptionFilter) {
992        final INotificationManager service = getService();
993        try {
994            service.setInterruptionFilter(mContext.getOpPackageName(), interruptionFilter);
995        } catch (RemoteException e) {
996            throw e.rethrowFromSystemServer();
997        }
998    }
999
1000    /** @hide */
1001    public static int zenModeToInterruptionFilter(int zen) {
1002        switch (zen) {
1003            case Global.ZEN_MODE_OFF: return INTERRUPTION_FILTER_ALL;
1004            case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return INTERRUPTION_FILTER_PRIORITY;
1005            case Global.ZEN_MODE_ALARMS: return INTERRUPTION_FILTER_ALARMS;
1006            case Global.ZEN_MODE_NO_INTERRUPTIONS: return INTERRUPTION_FILTER_NONE;
1007            default: return INTERRUPTION_FILTER_UNKNOWN;
1008        }
1009    }
1010
1011    /** @hide */
1012    public static int zenModeFromInterruptionFilter(int interruptionFilter, int defValue) {
1013        switch (interruptionFilter) {
1014            case INTERRUPTION_FILTER_ALL: return Global.ZEN_MODE_OFF;
1015            case INTERRUPTION_FILTER_PRIORITY: return Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
1016            case INTERRUPTION_FILTER_ALARMS: return Global.ZEN_MODE_ALARMS;
1017            case INTERRUPTION_FILTER_NONE:  return Global.ZEN_MODE_NO_INTERRUPTIONS;
1018            default: return defValue;
1019        }
1020    }
1021}
1022