diff --git a/api/current.txt b/api/current.txt index 8f933618e72cf..851cf4dd6c9e6 100644 --- a/api/current.txt +++ b/api/current.txt @@ -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"; @@ -33148,6 +33149,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(); @@ -33184,11 +33214,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 { diff --git a/api/system-current.txt b/api/system-current.txt index 7a9728025b43a..77a5c920b958e 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -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"; @@ -35265,6 +35266,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(); @@ -35308,11 +35338,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 { diff --git a/api/test-current.txt b/api/test-current.txt index ddb5b06425401..af92704201829 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -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"; @@ -33150,6 +33151,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(); @@ -33186,11 +33216,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 { diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java new file mode 100644 index 0000000000000..5d1317cf7d24e --- /dev/null +++ b/core/java/android/service/notification/NotificationAssistantService.java @@ -0,0 +1,191 @@ +/* + * 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. + *
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:
+ *+ * <service android:name=".NotificationAssistant" + * android:label="@string/service_name" + * android:permission="android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE"> + * <intent-filter> + * <action android:name="android.service.notification.NotificationAssistantService" /> + * </intent-filter> + * </service>+ */ +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. + } +} diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index ee97e8eeba8a0..d741f1a142ca4 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -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) { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 9bbbdca57eab7..77072aa33441f 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2607,6 +2607,14 @@