Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9fa689f8 authored by Chris Wren's avatar Chris Wren
Browse files

Notification Assistant API

This API allows a single assistant on the device to help the
user manage their notification stream by taking actions on
individual notifications:

  - modifying their priority up or down when they are posted
  - possibly changing if and how the notification interrupts the user
  - adding annotations under notifications

Bug: 22455414
Change-Id: Idf47972bb71c83f1dc1c9ec68a6fa92ac4fc522f
parent fc6e25ef
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ package android {
    field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
    field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
    field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
    field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE";
    field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
    field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
    field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
@@ -33140,6 +33141,35 @@ package android.service.notification {
    field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
  }
  public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
    ctor public NotificationAssistantService();
    method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
    method public final void clearAnnotation(java.lang.String);
    method public void onNotificationActionClick(java.lang.String, long, int);
    method public void onNotificationClick(java.lang.String, long);
    method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
    method public void onNotificationRemoved(java.lang.String, long, int);
    method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
    method public final void setAnnotation(java.lang.String, android.app.Notification);
    field public static final int REASON_APP_CANCEL = 8; // 0x8
    field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
    field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
    field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
    field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
    field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
    field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
    field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
    field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
    field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
    field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
    field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
    field public static final int REASON_USER_STOPPED = 6; // 0x6
  }
  public class NotificationAssistantService.Adjustment {
    ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
  }
  public abstract class NotificationListenerService extends android.app.Service {
    ctor public NotificationListenerService();
    method public final void cancelAllNotifications();
@@ -33176,11 +33206,19 @@ package android.service.notification {
  public static class NotificationListenerService.Ranking {
    ctor public NotificationListenerService.Ranking();
    method public int getImportance();
    method public java.lang.CharSequence getImportanceExplanation();
    method public java.lang.String getKey();
    method public int getRank();
    method public int getSuppressedVisualEffects();
    method public boolean isAmbient();
    method public boolean matchesInterruptionFilter();
    field public static final int IMPORTANCE_DEFAULT = 0; // 0x0
    field public static final int IMPORTANCE_HIGH = 1; // 0x1
    field public static final int IMPORTANCE_LOW = -1; // 0xffffffff
    field public static final int IMPORTANCE_MAX = 2; // 0x2
    field public static final int IMPORTANCE_NONE = -2; // 0xfffffffe
    field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
  }
  public static class NotificationListenerService.RankingMap implements android.os.Parcelable {
+38 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ package android {
    field public static final java.lang.String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET";
    field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
    field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
    field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE";
    field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
    field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
    field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
@@ -35256,6 +35257,35 @@ package android.service.notification {
    field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
  }
  public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
    ctor public NotificationAssistantService();
    method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
    method public final void clearAnnotation(java.lang.String);
    method public void onNotificationActionClick(java.lang.String, long, int);
    method public void onNotificationClick(java.lang.String, long);
    method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
    method public void onNotificationRemoved(java.lang.String, long, int);
    method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
    method public final void setAnnotation(java.lang.String, android.app.Notification);
    field public static final int REASON_APP_CANCEL = 8; // 0x8
    field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
    field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
    field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
    field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
    field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
    field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
    field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
    field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
    field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
    field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
    field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
    field public static final int REASON_USER_STOPPED = 6; // 0x6
  }
  public class NotificationAssistantService.Adjustment {
    ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
  }
  public abstract class NotificationListenerService extends android.app.Service {
    ctor public NotificationListenerService();
    method public final void cancelAllNotifications();
@@ -35299,11 +35329,19 @@ package android.service.notification {
  public static class NotificationListenerService.Ranking {
    ctor public NotificationListenerService.Ranking();
    method public int getImportance();
    method public java.lang.CharSequence getImportanceExplanation();
    method public java.lang.String getKey();
    method public int getRank();
    method public int getSuppressedVisualEffects();
    method public boolean isAmbient();
    method public boolean matchesInterruptionFilter();
    field public static final int IMPORTANCE_DEFAULT = 0; // 0x0
    field public static final int IMPORTANCE_HIGH = 1; // 0x1
    field public static final int IMPORTANCE_LOW = -1; // 0xffffffff
    field public static final int IMPORTANCE_MAX = 2; // 0x2
    field public static final int IMPORTANCE_NONE = -2; // 0xfffffffe
    field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
  }
  public static class NotificationListenerService.RankingMap implements android.os.Parcelable {
+38 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ package android {
    field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
    field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
    field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
    field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE";
    field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
    field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
    field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
@@ -33140,6 +33141,35 @@ package android.service.notification {
    field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
  }
  public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
    ctor public NotificationAssistantService();
    method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
    method public final void clearAnnotation(java.lang.String);
    method public void onNotificationActionClick(java.lang.String, long, int);
    method public void onNotificationClick(java.lang.String, long);
    method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
    method public void onNotificationRemoved(java.lang.String, long, int);
    method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
    method public final void setAnnotation(java.lang.String, android.app.Notification);
    field public static final int REASON_APP_CANCEL = 8; // 0x8
    field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
    field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
    field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
    field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
    field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
    field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
    field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
    field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
    field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
    field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
    field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
    field public static final int REASON_USER_STOPPED = 6; // 0x6
  }
  public class NotificationAssistantService.Adjustment {
    ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
  }
  public abstract class NotificationListenerService extends android.app.Service {
    ctor public NotificationListenerService();
    method public final void cancelAllNotifications();
@@ -33176,11 +33206,19 @@ package android.service.notification {
  public static class NotificationListenerService.Ranking {
    ctor public NotificationListenerService.Ranking();
    method public int getImportance();
    method public java.lang.CharSequence getImportanceExplanation();
    method public java.lang.String getKey();
    method public int getRank();
    method public int getSuppressedVisualEffects();
    method public boolean isAmbient();
    method public boolean matchesInterruptionFilter();
    field public static final int IMPORTANCE_DEFAULT = 0; // 0x0
    field public static final int IMPORTANCE_HIGH = 1; // 0x1
    field public static final int IMPORTANCE_LOW = -1; // 0xffffffff
    field public static final int IMPORTANCE_MAX = 2; // 0x2
    field public static final int IMPORTANCE_NONE = -2; // 0xfffffffe
    field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
  }
  public static class NotificationListenerService.RankingMap implements android.os.Parcelable {
+191 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.service.notification;

import android.app.Notification;
import android.net.Uri;

/**
 * A service that helps the user manage notifications by modifying the
 * relative importance of notifications.
 * <p>To extend this class, you must declare the service in your manifest file with
 * the {@link android.Manifest.permission#BIND_NOTIFICATION_ASSISTANT_SERVICE} permission
 * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
 * <pre>
 * &lt;service android:name=".NotificationAssistant"
 *          android:label="&#64;string/service_name"
 *          android:permission="android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE">
 *     &lt;intent-filter>
 *         &lt;action android:name="android.service.notification.NotificationAssistantService" />
 *     &lt;/intent-filter>
 * &lt;/service></pre>
 */
public abstract class NotificationAssistantService extends NotificationListenerService {
    /** Notification was canceled by the status bar reporting a click. */
    public static final int REASON_DELEGATE_CLICK = 1;

    /** Notification was canceled by the status bar reporting a user dismissal. */
    public static final int REASON_DELEGATE_CANCEL = 2;

    /** Notification was canceled by the status bar reporting a user dismiss all. */
    public static final int REASON_DELEGATE_CANCEL_ALL = 3;

    /** Notification was canceled by the status bar reporting an inflation error. */
    public static final int REASON_DELEGATE_ERROR = 4;

    /** Notification was canceled by the package manager modifying the package. */
    public static final int REASON_PACKAGE_CHANGED = 5;

    /** Notification was canceled by the owning user context being stopped. */
    public static final int REASON_USER_STOPPED = 6;

    /** Notification was canceled by the user banning the package. */
    public static final int REASON_PACKAGE_BANNED = 7;

    /** Notification was canceled by the app canceling this specific notification. */
    public static final int REASON_APP_CANCEL = 8;

    /** Notification was canceled by the app cancelling all its notifications. */
    public static final int REASON_APP_CANCEL_ALL = 9;

    /** Notification was canceled by a listener reporting a user dismissal. */
    public static final int REASON_LISTENER_CANCEL = 10;

    /** Notification was canceled by a listener reporting a user dismiss all. */
    public static final int REASON_LISTENER_CANCEL_ALL = 11;

    /** Notification was canceled because it was a member of a canceled group. */
    public static final int REASON_GROUP_SUMMARY_CANCELED = 12;

    /** Notification was canceled because it was an invisible member of a group. */
    public static final int REASON_GROUP_OPTIMIZATION = 13;

    public class Adjustment {
        int mImportance;
        CharSequence mExplanation;
        Uri mReference;

        /**
         * Create a notification importance adjustment.
         *
         * @param importance The final importance of the notification.
         * @param explanation A human-readable justification for the adjustment.
         * @param reference A reference to an external object that augments the
         *                  explanation, such as a
         *                  {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI},
         *                  or null.
         */
        public Adjustment(int importance, CharSequence explanation, Uri reference) {
            mImportance = importance;
            mExplanation = explanation;
            mReference = reference;
        }
    }

    /**
     * A notification was posted by an app. Called before alert.
     *
     * @param sbn the new notification
     * @param importance the initial importance of the notification.
     * @param user true if the initial importance reflects an explicit user preference.
     * @return an adjustment or null to take no action, within 100ms.
     */
    abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn,
          int importance, boolean user);

    /**
     * The visibility of a notification has changed.
     *
     * @param key the notification key
     * @param time milliseconds since midnight, January 1, 1970 UTC.
     * @param visible true if the notification became visible, false if hidden.
     */
    public void onNotificationVisibilityChanged(String key, long time, boolean visible)
    {
        // Do nothing, Override this to collect visibility statistics.
    }

    /**
     * The user clicked on a notification.
     *
     * @param key the notification key
     * @param time milliseconds since midnight, January 1, 1970 UTC.
     */
    public void onNotificationClick(String key, long time)
    {
        // Do nothing, Override this to collect click statistics
    }

    /**
     * The user clicked on a notification action.
     *
     * @param key the notification key
     * @param time milliseconds since midnight, January 1, 1970 UTC.
     * @param actionIndex the index of the action button that was pressed.
     */
    public void onNotificationActionClick(String key, long time, int actionIndex)
    {
        // Do nothing, Override this to collect action button click statistics
    }

    /**
     * A notification was removed.

     * @param key the notification key
     * @param time milliseconds since midnight, January 1, 1970 UTC.
     * @param reason see {@link #REASON_LISTENER_CANCEL}, etc.
     */
    public void onNotificationRemoved(String key, long time, int reason) {
        // Do nothing, Override this to collect dismissal statistics
    }

    /**
     * Change the importance of an existing notification.  N.B. this won’t cause
     * an existing notification to alert, but might allow a future update to
     * this notification to alert.
     *
     * @param key the notification key
     * @param adjustment the new importance with an explanation
     */
    public final void adjustImportance(String key, Adjustment adjustment)
    {
        // TODO: pack up the adjustment and send it to the NotificationManager.
    }

    /**
     * Add an annotation to a an existing notification. The delete intent will
     * be fired when the host notification is deleted, or when this annotation
     * is removed or replaced.
     *
     * @param key the notification key
     * @param annotation the new annotation object
     */
    public final void setAnnotation(String key, Notification annotation)
    {
        // TODO: pack up the annotation and send it to the NotificationManager.
    }

    /**
     * Remove the annotation from a notification.
     *
     * @param key the notification key
     */
    public final void clearAnnotation(String key)
    {
        // TODO: ask the NotificationManager to clear the annotation.
    }
}
+56 −1
Original line number Diff line number Diff line
@@ -822,6 +822,41 @@ public abstract class NotificationListenerService extends Service {
         * @hide */
        public static final int VISIBILITY_NO_OVERRIDE = -1000;

        /**
         * Value signifying thatn the has not expressed an importance.
         *
         * This value is for persisting preferences, and should never ve associated with
         * an actual notification.
         */
        public static final int IMPORTANCE_UNSPECIFIED = -1000;

        /**
         * A notification with no importance: shows nowhere, is blocked.
         */
        public static final int IMPORTANCE_NONE = -2;

        /**
         * Low notification importance: only shows in the shade, below the fold.
         */
        public static final int IMPORTANCE_LOW = -1;

        /**
         * Default notification importance: shows everywhere, but is not intrusive.
         */
        public static final int IMPORTANCE_DEFAULT = 0;

        /**
         * Higher notification importance: shows everywhere, makes noise,
         * but does not visually intrude.
         */
        public static final int IMPORTANCE_HIGH = 1;

        /**
         * Highest notification importance: shows everywhere, makes noise,
         * and also visually intrudes.
         */
        public static final int IMPORTANCE_MAX = 2;

        private String mKey;
        private int mRank = -1;
        private boolean mIsAmbient;
@@ -875,7 +910,6 @@ public abstract class NotificationListenerService extends Service {
            return mSuppressedVisualEffects;
        }


        /**
         * Returns whether the notification matches the user's interruption
         * filter.
@@ -887,6 +921,27 @@ public abstract class NotificationListenerService extends Service {
            return mMatchesInterruptionFilter;
        }

        /**
         * Returns the importance of the notification, which dictates its
         * modes of presentation, see: {@link #IMPORTANCE_DEFAULT}, etc.
         *
         * @return the rank of the notification
         */
        public int getImportance() {
            return IMPORTANCE_DEFAULT;  // TODO implement;
        }

        /**
         * If the importance has been overriden by user preference, or by a
         * {@link NotificationAssistantService}, then this will be non-null,
         * and should be displayed to the user.
         *
         * @return the explanation for the importance, or null if it is the natural importance
         */
        public CharSequence getImportanceExplanation() {
            return null;  // TODO implement
        }

        private void populate(String key, int rank, boolean isAmbient,
                boolean matchesInterruptionFilter, int visibilityOverride,
                int suppressedVisualEffects) {
Loading