diff options
author | John Spurlock <jspurlock@google.com> | 2015-05-08 22:28:49 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-05-08 22:28:51 +0000 |
commit | d89a6b2abc38907a532da7dec073663da5a74e7c (patch) | |
tree | d0ba1cec4ea6f69dda965770ca744bbe3b89400c | |
parent | 5759a8a9cfef08b7f9485c67b07be9ae268dea0a (diff) | |
parent | 807749301fcbda892dfc8a5832b19acf7d1cf53b (diff) | |
download | frameworks_base-d89a6b2abc38907a532da7dec073663da5a74e7c.zip frameworks_base-d89a6b2abc38907a532da7dec073663da5a74e7c.tar.gz frameworks_base-d89a6b2abc38907a532da7dec073663da5a74e7c.tar.bz2 |
Merge "Zen: Simplify notification policy api, add zenmode api." into mnc-dev
12 files changed, 361 insertions, 253 deletions
diff --git a/api/current.txt b/api/current.txt index f1865d5..07137f1 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5145,17 +5145,31 @@ package android.app { method public void cancel(java.lang.String, int); method public void cancelAll(); method public android.service.notification.StatusBarNotification[] getActiveNotifications(); - method public android.app.NotificationManager.Policy getNotificationPolicy(android.app.NotificationManager.Policy.Token); - method public boolean isNotificationPolicyTokenValid(android.app.NotificationManager.Policy.Token); + method public final int getCurrentInterruptionFilter(); + method public android.app.NotificationManager.Policy getNotificationPolicy(); + method public boolean isNotificationPolicyAccessGranted(); method public void notify(int, android.app.Notification); method public void notify(java.lang.String, int, android.app.Notification); - method public void requestNotificationPolicyToken(android.app.NotificationManager.Policy.Token.RequestCallback, android.os.Handler); - method public void setNotificationPolicy(android.app.NotificationManager.Policy.Token, android.app.NotificationManager.Policy); + method public void requestPolicyAccess(android.app.NotificationManager.NotificationPolicyAccessRequestCallback, android.os.Handler); + method public final void setInterruptionFilter(int); + method public void setNotificationPolicy(android.app.NotificationManager.Policy); + field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED"; field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED"; + 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 + field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2 + field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0 + } + + public static abstract class NotificationManager.NotificationPolicyAccessRequestCallback { + ctor public NotificationManager.NotificationPolicyAccessRequestCallback(); + method public abstract void onAccessDenied(); + method public abstract void onAccessGranted(); } public static class NotificationManager.Policy implements android.os.Parcelable { - ctor public NotificationManager.Policy(int, int); + ctor public NotificationManager.Policy(int, int, int); method public int describeContents(); method public static java.lang.String priorityCategoriesToString(int); method public static java.lang.String prioritySendersToString(int); @@ -5169,20 +5183,9 @@ package android.app { field public static final int PRIORITY_SENDERS_ANY = 0; // 0x0 field public static final int PRIORITY_SENDERS_CONTACTS = 1; // 0x1 field public static final int PRIORITY_SENDERS_STARRED = 2; // 0x2 + field public final int priorityCallSenders; field public final int priorityCategories; - field public final int prioritySenders; - } - - public static class NotificationManager.Policy.Token implements android.os.Parcelable { - method public int describeContents(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.app.NotificationManager.Policy.Token> CREATOR; - } - - public static abstract class NotificationManager.Policy.Token.RequestCallback { - ctor public NotificationManager.Policy.Token.RequestCallback(); - method public abstract void onTokenDenied(); - method public abstract void onTokenGranted(android.app.NotificationManager.Policy.Token); + field public final int priorityMessageSenders; } public final class PendingIntent implements android.os.Parcelable { @@ -26543,6 +26546,7 @@ package android.provider { field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS"; field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS"; field public static final java.lang.String ACTION_WIRELESS_SETTINGS = "android.settings.WIRELESS_SETTINGS"; + field public static final java.lang.String ACTION_ZEN_ACCESS_SETTINGS = "android.settings.ZEN_ACCESS_SETTINGS"; field public static final java.lang.String AUTHORITY = "settings"; field public static final java.lang.String EXTRA_ACCOUNT_TYPES = "account_types"; field public static final java.lang.String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled"; @@ -28842,7 +28846,6 @@ package android.service.notification { method public final int getCurrentInterruptionFilter(); method public final int getCurrentListenerHints(); method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking(); - method public final android.app.NotificationManager.Policy.Token getNotificationPolicyToken(); method public android.os.IBinder onBind(android.content.Intent); method public void onInterruptionFilterChanged(int); method public void onListenerConnected(); diff --git a/api/system-current.txt b/api/system-current.txt index aacb9a0..00da3d3 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5237,17 +5237,31 @@ package android.app { method public void cancel(java.lang.String, int); method public void cancelAll(); method public android.service.notification.StatusBarNotification[] getActiveNotifications(); - method public android.app.NotificationManager.Policy getNotificationPolicy(android.app.NotificationManager.Policy.Token); - method public boolean isNotificationPolicyTokenValid(android.app.NotificationManager.Policy.Token); + method public final int getCurrentInterruptionFilter(); + method public android.app.NotificationManager.Policy getNotificationPolicy(); + method public boolean isNotificationPolicyAccessGranted(); method public void notify(int, android.app.Notification); method public void notify(java.lang.String, int, android.app.Notification); - method public void requestNotificationPolicyToken(android.app.NotificationManager.Policy.Token.RequestCallback, android.os.Handler); - method public void setNotificationPolicy(android.app.NotificationManager.Policy.Token, android.app.NotificationManager.Policy); + method public void requestPolicyAccess(android.app.NotificationManager.NotificationPolicyAccessRequestCallback, android.os.Handler); + method public final void setInterruptionFilter(int); + method public void setNotificationPolicy(android.app.NotificationManager.Policy); + field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED"; field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED"; + 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 + field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2 + field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0 + } + + public static abstract class NotificationManager.NotificationPolicyAccessRequestCallback { + ctor public NotificationManager.NotificationPolicyAccessRequestCallback(); + method public abstract void onAccessDenied(); + method public abstract void onAccessGranted(); } public static class NotificationManager.Policy implements android.os.Parcelable { - ctor public NotificationManager.Policy(int, int); + ctor public NotificationManager.Policy(int, int, int); method public int describeContents(); method public static java.lang.String priorityCategoriesToString(int); method public static java.lang.String prioritySendersToString(int); @@ -5261,20 +5275,9 @@ package android.app { field public static final int PRIORITY_SENDERS_ANY = 0; // 0x0 field public static final int PRIORITY_SENDERS_CONTACTS = 1; // 0x1 field public static final int PRIORITY_SENDERS_STARRED = 2; // 0x2 + field public final int priorityCallSenders; field public final int priorityCategories; - field public final int prioritySenders; - } - - public static class NotificationManager.Policy.Token implements android.os.Parcelable { - method public int describeContents(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.app.NotificationManager.Policy.Token> CREATOR; - } - - public static abstract class NotificationManager.Policy.Token.RequestCallback { - ctor public NotificationManager.Policy.Token.RequestCallback(); - method public abstract void onTokenDenied(); - method public abstract void onTokenGranted(android.app.NotificationManager.Policy.Token); + field public final int priorityMessageSenders; } public final class PendingIntent implements android.os.Parcelable { @@ -28556,6 +28559,7 @@ package android.provider { field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS"; field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS"; field public static final java.lang.String ACTION_WIRELESS_SETTINGS = "android.settings.WIRELESS_SETTINGS"; + field public static final java.lang.String ACTION_ZEN_ACCESS_SETTINGS = "android.settings.ZEN_ACCESS_SETTINGS"; field public static final java.lang.String AUTHORITY = "settings"; field public static final java.lang.String EXTRA_ACCOUNT_TYPES = "account_types"; field public static final java.lang.String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled"; @@ -30896,7 +30900,6 @@ package android.service.notification { method public final int getCurrentInterruptionFilter(); method public final int getCurrentListenerHints(); method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking(); - method public final android.app.NotificationManager.Policy.Token getNotificationPolicyToken(); method public android.os.IBinder onBind(android.content.Intent); method public void onInterruptionFilterChanged(int); method public void onListenerConnected(); diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index ac8d5d8..63ff005 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -75,7 +75,7 @@ interface INotificationManager void requestInterruptionFilterFromListener(in INotificationListener token, int interruptionFilter); int getInterruptionFilterFromListener(in INotificationListener token); void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim); - NotificationManager.Policy.Token getPolicyTokenFromListener(in INotificationListener listener); + void setInterruptionFilter(String pkg, int interruptionFilter); ComponentName getEffectsSuppressor(); boolean matchesCallFilter(in Bundle extras); @@ -87,10 +87,13 @@ interface INotificationManager oneway void setZenMode(int mode, in Uri conditionId, String reason); oneway void notifyConditions(String pkg, in IConditionProvider provider, in Condition[] conditions); oneway void requestZenModeConditions(in IConditionListener callback, int relevance); - oneway void requestNotificationPolicyToken(String pkg, in INotificationManagerCallback callback); - boolean isNotificationPolicyTokenValid(String pkg, in NotificationManager.Policy.Token token); - NotificationManager.Policy getNotificationPolicy(in NotificationManager.Policy.Token token); - void setNotificationPolicy(in NotificationManager.Policy.Token token, in NotificationManager.Policy policy); + oneway void requestNotificationPolicyAccess(String pkg, in INotificationManagerCallback callback); + boolean isNotificationPolicyAccessGranted(String pkg); + NotificationManager.Policy getNotificationPolicy(String pkg); + void setNotificationPolicy(String pkg, in NotificationManager.Policy policy); + String[] getPackagesRequestingNotificationPolicyAccess(); + boolean isNotificationPolicyAccessGrantedForPackage(String pkg); + void setNotificationPolicyAccessGranted(String pkg, boolean granted); byte[] getBackupPayload(int user); void applyRestore(in byte[] payload, int user); diff --git a/core/java/android/app/INotificationManagerCallback.aidl b/core/java/android/app/INotificationManagerCallback.aidl index b9414ca..9929745 100644 --- a/core/java/android/app/INotificationManagerCallback.aidl +++ b/core/java/android/app/INotificationManagerCallback.aidl @@ -20,5 +20,5 @@ import android.app.NotificationManager; /** @hide */ oneway interface INotificationManagerCallback { - void onPolicyToken(in NotificationManager.Policy.Token token); + void onPolicyRequestResult(boolean granted); } diff --git a/core/java/android/app/NotificationManager.aidl b/core/java/android/app/NotificationManager.aidl index 8380b8d..a5d5671 100644 --- a/core/java/android/app/NotificationManager.aidl +++ b/core/java/android/app/NotificationManager.aidl @@ -17,4 +17,3 @@ package android.app; parcelable NotificationManager.Policy; -parcelable NotificationManager.Policy.Token;
\ No newline at end of file diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 0a59026..e4bbe27 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -20,7 +20,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.app.Notification.Builder; -import android.app.NotificationManager.Policy.Token; import android.content.ComponentName; import android.content.Context; import android.content.pm.ParceledListSlice; @@ -38,6 +37,7 @@ import android.provider.Settings.Global; import android.service.notification.IConditionListener; import android.service.notification.StatusBarNotification; import android.service.notification.ZenModeConfig; +import android.util.ArraySet; import android.util.Log; import java.util.Objects; @@ -107,6 +107,43 @@ public class NotificationManager public static final String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED"; + /** + * Intent that is broadcast when the state of getCurrentInterruptionFilter() changes. + * This broadcast is only sent to registered receivers. + */ + @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_INTERRUPTION_FILTER_CHANGED + = "android.app.action.INTERRUPTION_FILTER_CHANGED"; + + /** + * {@link #getCurrentInterruptionFilter() Interruption filter} constant - + * Normal interruption filter. + */ + public static final int INTERRUPTION_FILTER_ALL = 1; + + /** + * {@link #getCurrentInterruptionFilter() Interruption filter} constant - + * Priority interruption filter. + */ + public static final int INTERRUPTION_FILTER_PRIORITY = 2; + + /** + * {@link #getCurrentInterruptionFilter() Interruption filter} constant - + * No interruptions filter. + */ + public static final int INTERRUPTION_FILTER_NONE = 3; + + /** + * {@link #getCurrentInterruptionFilter() Interruption filter} constant - + * Alarms only interruption filter. + */ + public static final int INTERRUPTION_FILTER_ALARMS = 4; + + /** {@link #getCurrentInterruptionFilter() Interruption filter} constant - returned when + * the value is unavailable for any reason. + */ + public static final int INTERRUPTION_FILTER_UNKNOWN = 0; + private static INotificationManager sService; /** @hide */ @@ -357,29 +394,29 @@ public class NotificationManager } /** - * Requests a notification policy token for the calling package. + * Requests the ability to read/modify notification policy for the calling package. * - * @param callback required, used to receive the granted token or the deny signal. + * @param callback required, used to receive the granted or the denied signal. * @param handler The handler used when receiving the result. * If null, the current thread is used. */ - public void requestNotificationPolicyToken(@NonNull final Policy.Token.RequestCallback callback, + public void requestPolicyAccess(@NonNull final NotificationPolicyAccessRequestCallback callback, @Nullable Handler handler) { checkRequired("callback", callback); final Handler h = handler != null ? handler : new Handler(); INotificationManager service = getService(); try { - service.requestNotificationPolicyToken(mContext.getOpPackageName(), + service.requestNotificationPolicyAccess(mContext.getOpPackageName(), new INotificationManagerCallback.Stub() { @Override - public void onPolicyToken(final Token token) throws RemoteException { + public void onPolicyRequestResult(final boolean granted) throws RemoteException { h.post(new Runnable() { @Override public void run() { - if (token != null) { - callback.onTokenGranted(token); + if (granted) { + callback.onAccessGranted(); } else { - callback.onTokenDenied(); + callback.onAccessDenied(); } } }); @@ -389,16 +426,38 @@ public class NotificationManager } } + /** Callback for receiving the result of a policy access request. */ + public static abstract class NotificationPolicyAccessRequestCallback { + /** + * Received if the request was granted for this package. + */ + public abstract void onAccessGranted(); + + /** + * Received if the request was denied for this package. + */ + public abstract void onAccessDenied(); + } + /** - * Checks a given notification policy token. + * Checks the ability to read/modify notification policy for the calling package. * - * Returns true if the token is still valid for managing policy. + * Returns true if the calling package can read/modify notification policy. */ - public boolean isNotificationPolicyTokenValid(@NonNull Policy.Token token) { - if (token == null) return false; + public boolean isNotificationPolicyAccessGranted() { INotificationManager service = getService(); try { - return service.isNotificationPolicyTokenValid(mContext.getOpPackageName(), token); + return service.isNotificationPolicyAccessGranted(mContext.getOpPackageName()); + } catch (RemoteException e) { + } + return false; + } + + /** @hide */ + public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) { + INotificationManager service = getService(); + try { + return service.isNotificationPolicyAccessGrantedForPackage(pkg); } catch (RemoteException e) { } return false; @@ -407,13 +466,13 @@ public class NotificationManager /** * Gets the current notification policy. * - * @param token A valid notification policy token is required to access the current policy. + * <p> + * Only available if policy access is granted. */ - public Policy getNotificationPolicy(@NonNull Policy.Token token) { - checkRequired("token", token); + public Policy getNotificationPolicy() { INotificationManager service = getService(); try { - return service.getNotificationPolicy(token); + return service.getNotificationPolicy(mContext.getOpPackageName()); } catch (RemoteException e) { } return null; @@ -422,19 +481,46 @@ public class NotificationManager /** * Sets the current notification policy. * - * @param token A valid notification policy token is required to modify the current policy. + * <p> + * Only available if policy access is granted. + * * @param policy The new desired policy. */ - public void setNotificationPolicy(@NonNull Policy.Token token, @NonNull Policy policy) { - checkRequired("token", token); + public void setNotificationPolicy(@NonNull Policy policy) { checkRequired("policy", policy); INotificationManager service = getService(); try { - service.setNotificationPolicy(token, policy); + service.setNotificationPolicy(mContext.getOpPackageName(), policy); + } catch (RemoteException e) { + } + } + + /** @hide */ + public void setNotificationPolicyAccessGranted(String pkg, boolean granted) { + INotificationManager service = getService(); + try { + service.setNotificationPolicyAccessGranted(pkg, granted); } catch (RemoteException e) { } } + /** @hide */ + public ArraySet<String> getPackagesRequestingNotificationPolicyAccess() { + INotificationManager service = getService(); + try { + final String[] pkgs = service.getPackagesRequestingNotificationPolicyAccess(); + if (pkgs != null && pkgs.length > 0) { + final ArraySet<String> rt = new ArraySet<>(pkgs.length); + for (int i = 0; i < pkgs.length; i++) { + rt.add(pkgs[i]); + } + return rt; + } + } catch (RemoteException e) { + } + return new ArraySet<String>(); + } + private Context mContext; private static void checkRequired(String name, Object value) { @@ -477,24 +563,30 @@ public class NotificationManager /** Notification categories to prioritize. Bitmask of PRIORITY_CATEGORY_* constants. */ public final int priorityCategories; - /** Notification senders to prioritize. One of: + /** Notification senders to prioritize for calls. One of: + * PRIORITY_SENDERS_ANY, PRIORITY_SENDERS_CONTACTS, PRIORITY_SENDERS_STARRED */ + public final int priorityCallSenders; + + /** Notification senders to prioritize for messages. One of: * PRIORITY_SENDERS_ANY, PRIORITY_SENDERS_CONTACTS, PRIORITY_SENDERS_STARRED */ - public final int prioritySenders; + public final int priorityMessageSenders; - public Policy(int priorityCategories, int prioritySenders) { + public Policy(int priorityCategories, int priorityCallSenders, int priorityMessageSenders) { this.priorityCategories = priorityCategories; - this.prioritySenders = prioritySenders; + this.priorityCallSenders = priorityCallSenders; + this.priorityMessageSenders = priorityMessageSenders; } /** @hide */ public Policy(Parcel source) { - this(source.readInt(), source.readInt()); + this(source.readInt(), source.readInt(), source.readInt()); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(priorityCategories); - dest.writeInt(prioritySenders); + dest.writeInt(priorityCallSenders); + dest.writeInt(priorityMessageSenders); } @Override @@ -504,7 +596,7 @@ public class NotificationManager @Override public int hashCode() { - return Objects.hash(priorityCategories, prioritySenders); + return Objects.hash(priorityCategories, priorityCallSenders, priorityMessageSenders); } @Override @@ -513,14 +605,16 @@ public class NotificationManager if (o == this) return true; final Policy other = (Policy) o; return other.priorityCategories == priorityCategories - && other.prioritySenders == prioritySenders; + && other.priorityCallSenders == priorityCallSenders + && other.priorityMessageSenders == priorityMessageSenders; } @Override public String toString() { return "NotificationManager.Policy[" + "priorityCategories=" + priorityCategoriesToString(priorityCategories) - + ",prioritySenders=" + prioritySendersToString(prioritySenders) + + ",priorityCallSenders=" + prioritySendersToString(priorityCallSenders) + + ",priorityMessageSenders=" + prioritySendersToString(priorityMessageSenders) + "]"; } @@ -574,75 +668,6 @@ public class NotificationManager } }; - /** - * Represents a client-specific token required to manage notification policy. - */ - public static class Token implements Parcelable { - private final IBinder mBinder; - - /** @hide */ - public Token(IBinder binder) { - if (binder == null) throw new IllegalArgumentException("Binder required for token"); - mBinder = binder; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public int hashCode() { - return Objects.hash(mBinder); - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof Token)) return false; - if (o == this) return true; - final Token other = (Token) o; - return Objects.equals(other.mBinder, mBinder); - } - - @Override - public String toString() { - return String.format("NotificationManager.Token[0x%08x]", - System.identityHashCode(mBinder)); - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeStrongBinder(mBinder); - } - - public static final Parcelable.Creator<Token> CREATOR - = new Parcelable.Creator<Token>() { - @Override - public Token createFromParcel(Parcel in) { - return new Token(in.readStrongBinder()); - } - - @Override - public Token[] newArray(int size) { - return new Token[size]; - } - }; - - /** Callback for receiving the result of a token request. */ - public static abstract class RequestCallback { - /** - * Received if the request was granted for this package. - * - * @param token can be used to manage notification policy. - */ - public abstract void onTokenGranted(Policy.Token token); - - /** - * Received if the request was denied for this package. - */ - public abstract void onTokenDenied(); - } - } } /** @@ -671,4 +696,69 @@ public class NotificationManager } return new StatusBarNotification[0]; } + + /** + * Gets the current notification interruption filter. + * + * <p> + * The interruption filter defines which notifications are allowed to interrupt the user + * (e.g. via sound & vibration) and is applied globally. + * @return One of the INTERRUPTION_FILTER_ constants, or INTERRUPTION_FILTER_UNKNOWN when + * unavailable. + * + * <p> + * Only available if policy access is granted. + */ + public final int getCurrentInterruptionFilter() { + final INotificationManager service = getService(); + try { + return zenModeToInterruptionFilter(service.getZenMode()); + } catch (RemoteException e) { + Log.e(TAG, "Unable to talk to notification manager. Woe!", e); + } + return INTERRUPTION_FILTER_UNKNOWN; + } + + /** + * Sets the current notification interruption filter. + * + * <p> + * The interruption filter defines which notifications are allowed to interrupt the user + * (e.g. via sound & vibration) and is applied globally. + * @return One of the INTERRUPTION_FILTER_ constants, or INTERRUPTION_FILTER_UNKNOWN when + * unavailable. + * + * <p> + * Only available if policy access is granted. + */ + public final void setInterruptionFilter(int interruptionFilter) { + final INotificationManager service = getService(); + try { + service.setInterruptionFilter(mContext.getOpPackageName(), interruptionFilter); + } catch (RemoteException e) { + Log.e(TAG, "Unable to talk to notification manager. Woe!", e); + } + } + + /** @hide */ + public static int zenModeToInterruptionFilter(int zen) { + switch (zen) { + case Global.ZEN_MODE_OFF: return INTERRUPTION_FILTER_ALL; + case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return INTERRUPTION_FILTER_PRIORITY; + case Global.ZEN_MODE_ALARMS: return INTERRUPTION_FILTER_ALARMS; + case Global.ZEN_MODE_NO_INTERRUPTIONS: return INTERRUPTION_FILTER_NONE; + default: return INTERRUPTION_FILTER_UNKNOWN; + } + } + + /** @hide */ + public static int zenModeFromInterruptionFilter(int interruptionFilter, int defValue) { + switch (interruptionFilter) { + case INTERRUPTION_FILTER_ALL: return Global.ZEN_MODE_OFF; + case INTERRUPTION_FILTER_PRIORITY: return Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + case INTERRUPTION_FILTER_ALARMS: return Global.ZEN_MODE_ALARMS; + case INTERRUPTION_FILTER_NONE: return Global.ZEN_MODE_NO_INTERRUPTIONS; + default: return defValue; + } + } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 7c3c11b..dc70d7b 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -809,6 +809,18 @@ public final class Settings { = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"; /** + * Activity Action: Show Do Not Disturb access settings. + * <p> + * In some cases, a matching Activity may not exist, so ensure you safeguard against this. + * <p> + * Input: Nothing. + * <p> + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_ZEN_ACCESS_SETTINGS = "android.settings.ZEN_ACCESS_SETTINGS"; + + /** * @hide */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 35b8819..7956a3f 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -21,7 +21,7 @@ import android.annotation.SdkConstant; import android.app.INotificationManager; import android.app.Notification; import android.app.Notification.Builder; -import android.app.NotificationManager.Policy; +import android.app.NotificationManager; import android.app.Service; import android.content.ComponentName; import android.content.Context; @@ -64,25 +64,29 @@ public abstract class NotificationListenerService extends Service { * {@link #getCurrentInterruptionFilter() Interruption filter} constant - * Normal interruption filter. */ - public static final int INTERRUPTION_FILTER_ALL = 1; + public static final int INTERRUPTION_FILTER_ALL + = NotificationManager.INTERRUPTION_FILTER_ALL; /** * {@link #getCurrentInterruptionFilter() Interruption filter} constant - * Priority interruption filter. */ - public static final int INTERRUPTION_FILTER_PRIORITY = 2; + public static final int INTERRUPTION_FILTER_PRIORITY + = NotificationManager.INTERRUPTION_FILTER_PRIORITY; /** * {@link #getCurrentInterruptionFilter() Interruption filter} constant - * No interruptions filter. */ - public static final int INTERRUPTION_FILTER_NONE = 3; + public static final int INTERRUPTION_FILTER_NONE + = NotificationManager.INTERRUPTION_FILTER_NONE; /** * {@link #getCurrentInterruptionFilter() Interruption filter} constant - * Alarms only interruption filter. */ - public static final int INTERRUPTION_FILTER_ALARMS = 4; + public static final int INTERRUPTION_FILTER_ALARMS + = NotificationManager.INTERRUPTION_FILTER_ALARMS; /** {@link #getCurrentInterruptionFilter() Interruption filter} constant - returned when * the value is unavailable for any reason. For example, before the notification listener @@ -90,7 +94,8 @@ public abstract class NotificationListenerService extends Service { * * {@see #onListenerConnected()} */ - public static final int INTERRUPTION_FILTER_UNKNOWN = 0; + public static final int INTERRUPTION_FILTER_UNKNOWN + = NotificationManager.INTERRUPTION_FILTER_UNKNOWN; /** {@link #getCurrentListenerHints() Listener hints} constant - the primary device UI * should disable notification sound, vibrating and other visual or aural effects. @@ -516,22 +521,6 @@ public abstract class NotificationListenerService extends Service { } /** - * Gets the notification policy token associated with this listener. - * - * <p> - * Returns null if this listener is not currently active. - */ - public final Policy.Token getNotificationPolicyToken() { - if (!isBound()) return null; - try { - return getNotificationInterface().getPolicyTokenFromListener(mWrapper); - } catch (android.os.RemoteException ex) { - Log.v(TAG, "Unable to contact notification manager", ex); - return null; - } - } - - /** * Sets the desired {@link #getCurrentListenerHints() listener hints}. * * <p> diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 26bd10f..20b8cbe 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -538,7 +538,7 @@ public class ZenModeConfig implements Parcelable { } priorityCallSenders = sourceToPrioritySenders(allowCallsFrom, priorityCallSenders); priorityMessageSenders = sourceToPrioritySenders(allowMessagesFrom, priorityMessageSenders); - return new Policy(priorityCategories, priorityCallSenders); + return new Policy(priorityCategories, priorityCallSenders, priorityMessageSenders); } private static int sourceToPrioritySenders(int source, int def) { @@ -567,7 +567,9 @@ public class ZenModeConfig implements Parcelable { allowReminders = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_REMINDERS) != 0; allowRepeatCallers = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_REPEAT_CALLERS) != 0; - allowCallsFrom = prioritySendersToSource(policy.prioritySenders, allowCallsFrom); + allowCallsFrom = prioritySendersToSource(policy.priorityCallSenders, allowCallsFrom); + allowMessagesFrom = prioritySendersToSource(policy.priorityMessageSenders, + allowMessagesFrom); } public static Condition toTimeCondition(Context context, int minutesFromNow, int userHandle) { diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index b92c734..6f8e3ca 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -189,6 +189,10 @@ abstract public class ManagedServices { } } + public boolean isComponentEnabledForPackage(String pkg) { + return mEnabledServicesPackageNames.contains(pkg); + } + public void onPackagesChanged(boolean queryReplace, String[] pkgList) { if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList)) diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 25998da..791c1de 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -37,7 +37,6 @@ import android.app.NotificationManager.Policy; import android.app.PendingIntent; import android.app.StatusBarManager; import android.app.usage.UsageEvents; -import android.app.usage.UsageStats; import android.app.usage.UsageStatsManagerInternal; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -233,7 +232,7 @@ public class NotificationManagerService extends SystemService { new ArrayMap<String, NotificationRecord>(); final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>(); final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>(); - private final ArrayMap<String, Policy.Token> mPolicyTokens = new ArrayMap<>(); + private final ArrayMap<String, Boolean> mPolicyAccess = new ArrayMap<>(); // The last key in this list owns the hardware. @@ -899,6 +898,7 @@ public class NotificationManagerService extends SystemService { @Override void onZenModeChanged() { + sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED); synchronized(mNotificationList) { updateInterruptionFilterLocked(); } @@ -906,9 +906,12 @@ public class NotificationManagerService extends SystemService { @Override void onPolicyChanged() { - getContext().sendBroadcast( - new Intent(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED) - .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)); + sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED); + } + + private void sendRegisteredOnlyBroadcast(String action) { + getContext().sendBroadcast(new Intent(action) + .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)); } }); final File systemDir = new File(Environment.getDataDirectory(), "system"); @@ -1607,6 +1610,19 @@ public class NotificationManagerService extends SystemService { } @Override + public void setInterruptionFilter(String pkg, int filter) throws RemoteException { + enforcePolicyAccess(pkg, "setInterruptionFilter"); + final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1); + if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter); + final long identity = Binder.clearCallingIdentity(); + try { + mZenModeHelper.setManualZenMode(zen, null, "setInterruptionFilter"); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override public void notifyConditions(String pkg, IConditionProvider provider, Condition[] conditions) { final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider); @@ -1641,16 +1657,19 @@ public class NotificationManagerService extends SystemService { message); } - private void enforcePolicyToken(Policy.Token token, String method) { - if (!checkPolicyToken(token)) { - Slog.w(TAG, "Invalid notification policy token calling " + method); - throw new SecurityException("Invalid notification policy token"); + private void enforcePolicyAccess(String pkg, String method) { + if (!checkPolicyAccess(pkg)) { + Slog.w(TAG, "Notification policy access denied calling " + method); + throw new SecurityException("Notification policy access denied"); } } - private boolean checkPolicyToken(Policy.Token token) { - return mPolicyTokens.containsValue(token) - || mListeners.mPolicyTokens.containsValue(token); + private boolean checkPackagePolicyAccess(String pkg) { + return Boolean.TRUE.equals(mPolicyAccess.get(pkg)); + } + + private boolean checkPolicyAccess(String pkg) { + return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg); } @Override @@ -1702,52 +1721,76 @@ public class NotificationManagerService extends SystemService { } @Override - public Policy.Token getPolicyTokenFromListener(INotificationListener listener) { + public void requestNotificationPolicyAccess(String pkg, + INotificationManagerCallback callback) throws RemoteException { + if (callback == null) { + Slog.w(TAG, "requestNotificationPolicyAccess: no callback specified"); + return; + } + if (pkg == null) { + Slog.w(TAG, "requestNotificationPolicyAccess denied: no package specified"); + callback.onPolicyRequestResult(false); + return; + } final long identity = Binder.clearCallingIdentity(); try { - return mListeners.getPolicyToken(listener); + synchronized (mNotificationList) { + // immediately grant for now + mPolicyAccess.put(pkg, true); + if (DBG) Slog.w(TAG, "requestNotificationPolicyAccess granted for " + pkg); + } } finally { Binder.restoreCallingIdentity(identity); } + callback.onPolicyRequestResult(true); } @Override - public void requestNotificationPolicyToken(String pkg, - INotificationManagerCallback callback) throws RemoteException { - if (callback == null) { - Slog.w(TAG, "requestNotificationPolicyToken: no callback specified"); - return; - } - if (pkg == null) { - Slog.w(TAG, "requestNotificationPolicyToken denied: no package specified"); - callback.onPolicyToken(null); - return; - } - Policy.Token token = null; + public boolean isNotificationPolicyAccessGranted(String pkg) { + return checkPolicyAccess(pkg); + } + + @Override + public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) { + enforceSystemOrSystemUI("request policy access status for another package"); + return checkPackagePolicyAccess(pkg); + } + + @Override + public String[] getPackagesRequestingNotificationPolicyAccess() + throws RemoteException { + enforceSystemOrSystemUI("request policy access packages"); final long identity = Binder.clearCallingIdentity(); try { synchronized (mNotificationList) { - token = mPolicyTokens.get(pkg); - if (token == null) { - token = new Policy.Token(new Binder()); - mPolicyTokens.put(pkg, token); + final String[] rt = new String[mPolicyAccess.size()]; + for (int i = 0; i < mPolicyAccess.size(); i++) { + rt[i] = mPolicyAccess.keyAt(i); } - if (DBG) Slog.w(TAG, "requestNotificationPolicyToken granted for " + pkg); + return rt; } } finally { Binder.restoreCallingIdentity(identity); } - callback.onPolicyToken(token); } @Override - public boolean isNotificationPolicyTokenValid(String pkg, Policy.Token token) { - return checkPolicyToken(token); + public void setNotificationPolicyAccessGranted(String pkg, boolean granted) + throws RemoteException { + enforceSystemOrSystemUI("grant notification policy access"); + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mNotificationList) { + mPolicyAccess.put(pkg, granted); + } + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override - public Policy getNotificationPolicy(Policy.Token token) { - enforcePolicyToken(token, "getNotificationPolicy"); + public Policy getNotificationPolicy(String pkg) { + enforcePolicyAccess(pkg, "getNotificationPolicy"); final long identity = Binder.clearCallingIdentity(); try { return mZenModeHelper.getNotificationPolicy(); @@ -1757,8 +1800,8 @@ public class NotificationManagerService extends SystemService { } @Override - public void setNotificationPolicy(Policy.Token token, Policy policy) { - enforcePolicyToken(token, "setNotificationPolicy"); + public void setNotificationPolicy(String pkg, Policy policy) { + enforcePolicyAccess(pkg, "setNotificationPolicy"); final long identity = Binder.clearCallingIdentity(); try { mZenModeHelper.setNotificationPolicy(policy); @@ -1881,11 +1924,9 @@ public class NotificationManagerService extends SystemService { pw.print(listener.component); } pw.println(')'); - pw.print(" mPolicyTokens.keys: "); - pw.println(TextUtils.join(",", mPolicyTokens.keySet())); - pw.print(" mListeners.mPolicyTokens.keys: "); - pw.println(TextUtils.join(",", mListeners.mPolicyTokens.keySet())); } + pw.println("\n Policy access:"); + pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess); pw.println("\n Condition providers:"); mConditionProviders.dump(pw, filter); @@ -3138,18 +3179,12 @@ public class NotificationManagerService extends SystemService { public class NotificationListeners extends ManagedServices { private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); - private final ArrayMap<ComponentName, Policy.Token> mPolicyTokens = new ArrayMap<>(); private boolean mNotificationGroupsDesired; public NotificationListeners() { super(getContext(), mHandler, mNotificationList, mUserProfiles); } - public Policy.Token getPolicyToken(INotificationListener listener) { - final ManagedServiceInfo info = checkServiceTokenLocked(listener); - return info == null ? null : mPolicyTokens.get(info.component); - } - @Override protected Config getConfig() { Config c = new Config(); @@ -3174,7 +3209,6 @@ public class NotificationManagerService extends SystemService { synchronized (mNotificationList) { updateNotificationGroupsDesiredLocked(); update = makeRankingUpdateLocked(info); - mPolicyTokens.put(info.component, new Policy.Token(new Binder())); } try { listener.onListenerConnected(update); @@ -3191,7 +3225,6 @@ public class NotificationManagerService extends SystemService { } mLightTrimListeners.remove(removed); updateNotificationGroupsDesiredLocked(); - mPolicyTokens.remove(removed.component); } public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) { diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index e97def8..ca354e0 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -22,6 +22,7 @@ import static android.media.AudioAttributes.USAGE_NOTIFICATION; import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; import android.app.AppOpsManager; +import android.app.NotificationManager; import android.app.NotificationManager.Policy; import android.content.ComponentName; import android.content.ContentResolver; @@ -142,11 +143,11 @@ public class ZenModeHelper { } public int getZenModeListenerInterruptionFilter() { - return getZenModeListenerInterruptionFilter(mZenMode); + return NotificationManager.zenModeToInterruptionFilter(mZenMode); } - public void requestFromListener(ComponentName name, int interruptionFilter) { - final int newZen = zenModeFromListenerInterruptionFilter(interruptionFilter, -1); + public void requestFromListener(ComponentName name, int filter) { + final int newZen = NotificationManager.zenModeFromInterruptionFilter(filter, -1); if (newZen != -1) { setManualZenMode(newZen, null, "listener:" + (name != null ? name.flattenToShortString() : null)); @@ -393,37 +394,6 @@ public class ZenModeHelper { } } - private static int getZenModeListenerInterruptionFilter(int zen) { - switch (zen) { - case Global.ZEN_MODE_OFF: - return NotificationListenerService.INTERRUPTION_FILTER_ALL; - case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: - return NotificationListenerService.INTERRUPTION_FILTER_PRIORITY; - case Global.ZEN_MODE_ALARMS: - return NotificationListenerService.INTERRUPTION_FILTER_ALARMS; - case Global.ZEN_MODE_NO_INTERRUPTIONS: - return NotificationListenerService.INTERRUPTION_FILTER_NONE; - default: - return 0; - } - } - - private static int zenModeFromListenerInterruptionFilter(int listenerInterruptionFilter, - int defValue) { - switch (listenerInterruptionFilter) { - case NotificationListenerService.INTERRUPTION_FILTER_ALL: - return Global.ZEN_MODE_OFF; - case NotificationListenerService.INTERRUPTION_FILTER_PRIORITY: - return Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; - case NotificationListenerService.INTERRUPTION_FILTER_ALARMS: - return Global.ZEN_MODE_ALARMS; - case NotificationListenerService.INTERRUPTION_FILTER_NONE: - return Global.ZEN_MODE_NO_INTERRUPTIONS; - default: - return defValue; - } - } - private ZenModeConfig readDefaultConfig(Resources resources) { XmlResourceParser parser = null; try { |