Merge "Zen: Add notification policy management api."
This commit is contained in:
committed by
Android (Google) Code Review
commit
a419dd1616
@@ -74,6 +74,7 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/app/IBackupAgent.aidl \
|
||||
core/java/android/app/IInstrumentationWatcher.aidl \
|
||||
core/java/android/app/INotificationManager.aidl \
|
||||
core/java/android/app/INotificationManagerCallback.aidl \
|
||||
core/java/android/app/IProcessObserver.aidl \
|
||||
core/java/android/app/ISearchManager.aidl \
|
||||
core/java/android/app/ISearchManagerCallback.aidl \
|
||||
@@ -555,6 +556,7 @@ aidl_files := \
|
||||
frameworks/base/core/java/android/app/AssistStructure.aidl \
|
||||
frameworks/base/core/java/android/app/AssistContent.aidl \
|
||||
frameworks/base/core/java/android/app/Notification.aidl \
|
||||
frameworks/base/core/java/android/app/NotificationManager.aidl \
|
||||
frameworks/base/core/java/android/app/WallpaperInfo.aidl \
|
||||
frameworks/base/core/java/android/app/AppOpsManager.aidl \
|
||||
frameworks/base/core/java/android/app/ActivityManager.aidl \
|
||||
|
||||
@@ -5108,8 +5108,44 @@ package android.app {
|
||||
method public void cancel(int);
|
||||
method public void cancel(java.lang.String, int);
|
||||
method public void cancelAll();
|
||||
method public android.app.NotificationManager.Policy getNotificationPolicy(android.app.NotificationManager.Policy.Token);
|
||||
method public boolean isNotificationPolicyTokenValid(android.app.NotificationManager.Policy.Token);
|
||||
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);
|
||||
field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
|
||||
}
|
||||
|
||||
public static class NotificationManager.Policy implements android.os.Parcelable {
|
||||
ctor public NotificationManager.Policy(int, int);
|
||||
method public int describeContents();
|
||||
method public static java.lang.String priorityCategoriesToString(int);
|
||||
method public static java.lang.String prioritySendersToString(int);
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<android.app.NotificationManager.Policy> CREATOR;
|
||||
field public static final int PRIORITY_CATEGORY_CALLS = 8; // 0x8
|
||||
field public static final int PRIORITY_CATEGORY_EVENTS = 2; // 0x2
|
||||
field public static final int PRIORITY_CATEGORY_MESSAGES = 4; // 0x4
|
||||
field public static final int PRIORITY_CATEGORY_REMINDERS = 1; // 0x1
|
||||
field public static final int PRIORITY_CATEGORY_REPEAT_CALLERS = 16; // 0x10
|
||||
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 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);
|
||||
}
|
||||
|
||||
public final class PendingIntent implements android.os.Parcelable {
|
||||
@@ -28603,6 +28639,7 @@ 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();
|
||||
|
||||
@@ -5199,8 +5199,44 @@ package android.app {
|
||||
method public void cancel(int);
|
||||
method public void cancel(java.lang.String, int);
|
||||
method public void cancelAll();
|
||||
method public android.app.NotificationManager.Policy getNotificationPolicy(android.app.NotificationManager.Policy.Token);
|
||||
method public boolean isNotificationPolicyTokenValid(android.app.NotificationManager.Policy.Token);
|
||||
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);
|
||||
field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
|
||||
}
|
||||
|
||||
public static class NotificationManager.Policy implements android.os.Parcelable {
|
||||
ctor public NotificationManager.Policy(int, int);
|
||||
method public int describeContents();
|
||||
method public static java.lang.String priorityCategoriesToString(int);
|
||||
method public static java.lang.String prioritySendersToString(int);
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<android.app.NotificationManager.Policy> CREATOR;
|
||||
field public static final int PRIORITY_CATEGORY_CALLS = 8; // 0x8
|
||||
field public static final int PRIORITY_CATEGORY_EVENTS = 2; // 0x2
|
||||
field public static final int PRIORITY_CATEGORY_MESSAGES = 4; // 0x4
|
||||
field public static final int PRIORITY_CATEGORY_REMINDERS = 1; // 0x1
|
||||
field public static final int PRIORITY_CATEGORY_REPEAT_CALLERS = 16; // 0x10
|
||||
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 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);
|
||||
}
|
||||
|
||||
public final class PendingIntent implements android.os.Parcelable {
|
||||
@@ -30646,6 +30682,7 @@ 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();
|
||||
|
||||
@@ -17,8 +17,10 @@
|
||||
|
||||
package android.app;
|
||||
|
||||
import android.app.INotificationManagerCallback;
|
||||
import android.app.ITransientNotification;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
@@ -71,6 +73,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);
|
||||
|
||||
ComponentName getEffectsSuppressor();
|
||||
boolean matchesCallFilter(in Bundle extras);
|
||||
@@ -82,4 +85,8 @@ 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);
|
||||
}
|
||||
|
||||
24
core/java/android/app/INotificationManagerCallback.aidl
Normal file
24
core/java/android/app/INotificationManagerCallback.aidl
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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.app;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
|
||||
/** @hide */
|
||||
oneway interface INotificationManagerCallback {
|
||||
void onPolicyToken(in NotificationManager.Policy.Token token);
|
||||
}
|
||||
20
core/java/android/app/NotificationManager.aidl
Normal file
20
core/java/android/app/NotificationManager.aidl
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* 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.app;
|
||||
|
||||
parcelable NotificationManager.Policy;
|
||||
parcelable NotificationManager.Policy.Token;
|
||||
@@ -16,14 +16,19 @@
|
||||
|
||||
package android.app;
|
||||
|
||||
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.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.StrictMode;
|
||||
@@ -33,6 +38,8 @@ import android.service.notification.IConditionListener;
|
||||
import android.service.notification.ZenModeConfig;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Class to notify the user of events that happen. This is how you tell
|
||||
* the user that something has happened in the background. {@more}
|
||||
@@ -89,6 +96,14 @@ public class NotificationManager
|
||||
public static final String ACTION_EFFECTS_SUPPRESSOR_CHANGED
|
||||
= "android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED";
|
||||
|
||||
/**
|
||||
* Intent that is broadcast when the state of getNotificationPolicy() changes.
|
||||
* This broadcast is only sent to registered receivers.
|
||||
*/
|
||||
@SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_NOTIFICATION_POLICY_CHANGED
|
||||
= "android.app.action.NOTIFICATION_POLICY_CHANGED";
|
||||
|
||||
private static INotificationManager sService;
|
||||
|
||||
/** @hide */
|
||||
@@ -338,5 +353,293 @@ public class NotificationManager
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests a notification policy token for the calling package.
|
||||
*
|
||||
* @param callback required, used to receive the granted token or the deny 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,
|
||||
@Nullable Handler handler) {
|
||||
checkRequired("callback", callback);
|
||||
final Handler h = handler != null ? handler : new Handler();
|
||||
INotificationManager service = getService();
|
||||
try {
|
||||
service.requestNotificationPolicyToken(mContext.getOpPackageName(),
|
||||
new INotificationManagerCallback.Stub() {
|
||||
@Override
|
||||
public void onPolicyToken(final Token token) throws RemoteException {
|
||||
h.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (token != null) {
|
||||
callback.onTokenGranted(token);
|
||||
} else {
|
||||
callback.onTokenDenied();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a given notification policy token.
|
||||
*
|
||||
* Returns true if the token is still valid for managing policy.
|
||||
*/
|
||||
public boolean isNotificationPolicyTokenValid(@NonNull Policy.Token token) {
|
||||
if (token == null) return false;
|
||||
INotificationManager service = getService();
|
||||
try {
|
||||
return service.isNotificationPolicyTokenValid(mContext.getOpPackageName(), token);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current notification policy.
|
||||
*
|
||||
* @param token A valid notification policy token is required to access the current policy.
|
||||
*/
|
||||
public Policy getNotificationPolicy(@NonNull Policy.Token token) {
|
||||
checkRequired("token", token);
|
||||
INotificationManager service = getService();
|
||||
try {
|
||||
return service.getNotificationPolicy(token);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current notification policy.
|
||||
*
|
||||
* @param token A valid notification policy token is required to modify the current policy.
|
||||
* @param policy The new desired policy.
|
||||
*/
|
||||
public void setNotificationPolicy(@NonNull Policy.Token token, @NonNull Policy policy) {
|
||||
checkRequired("token", token);
|
||||
checkRequired("policy", policy);
|
||||
INotificationManager service = getService();
|
||||
try {
|
||||
service.setNotificationPolicy(token, policy);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
private Context mContext;
|
||||
|
||||
private static void checkRequired(String name, Object value) {
|
||||
if (value == null) {
|
||||
throw new IllegalArgumentException(name + " is required");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification policy configuration. Represents user-preferences for notification
|
||||
* filtering and prioritization.
|
||||
*/
|
||||
public static class Policy implements android.os.Parcelable {
|
||||
/** Reminder notifications are prioritized. */
|
||||
public static final int PRIORITY_CATEGORY_REMINDERS = 1 << 0;
|
||||
/** Event notifications are prioritized. */
|
||||
public static final int PRIORITY_CATEGORY_EVENTS = 1 << 1;
|
||||
/** Message notifications are prioritized. */
|
||||
public static final int PRIORITY_CATEGORY_MESSAGES = 1 << 2;
|
||||
/** Calls are prioritized. */
|
||||
public static final int PRIORITY_CATEGORY_CALLS = 1 << 3;
|
||||
/** Calls from repeat callers are prioritized. */
|
||||
public static final int PRIORITY_CATEGORY_REPEAT_CALLERS = 1 << 4;
|
||||
|
||||
private static final int[] ALL_PRIORITY_CATEGORIES = {
|
||||
PRIORITY_CATEGORY_REMINDERS,
|
||||
PRIORITY_CATEGORY_EVENTS,
|
||||
PRIORITY_CATEGORY_MESSAGES,
|
||||
PRIORITY_CATEGORY_CALLS,
|
||||
PRIORITY_CATEGORY_REPEAT_CALLERS,
|
||||
};
|
||||
|
||||
/** Any sender is prioritized. */
|
||||
public static final int PRIORITY_SENDERS_ANY = 0;
|
||||
/** Saved contacts are prioritized. */
|
||||
public static final int PRIORITY_SENDERS_CONTACTS = 1;
|
||||
/** Only starred contacts are prioritized. */
|
||||
public static final int PRIORITY_SENDERS_STARRED = 2;
|
||||
|
||||
/** Notification categories to prioritize. Bitmask of PRIORITY_CATEGORY_* constants. */
|
||||
public final int priorityCategories;
|
||||
|
||||
/** Notification senders to prioritize. One of:
|
||||
* PRIORITY_SENDERS_ANY, PRIORITY_SENDERS_CONTACTS, PRIORITY_SENDERS_STARRED */
|
||||
public final int prioritySenders;
|
||||
|
||||
public Policy(int priorityCategories, int prioritySenders) {
|
||||
this.priorityCategories = priorityCategories;
|
||||
this.prioritySenders = prioritySenders;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public Policy(Parcel source) {
|
||||
this(source.readInt(), source.readInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(priorityCategories);
|
||||
dest.writeInt(prioritySenders);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(priorityCategories, prioritySenders);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Policy)) return false;
|
||||
if (o == this) return true;
|
||||
final Policy other = (Policy) o;
|
||||
return other.priorityCategories == priorityCategories
|
||||
&& other.prioritySenders == prioritySenders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NotificationManager.Policy["
|
||||
+ "priorityCategories=" + priorityCategoriesToString(priorityCategories)
|
||||
+ ",prioritySenders=" + prioritySendersToString(prioritySenders)
|
||||
+ "]";
|
||||
}
|
||||
|
||||
public static String priorityCategoriesToString(int priorityCategories) {
|
||||
if (priorityCategories == 0) return "";
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < ALL_PRIORITY_CATEGORIES.length; i++) {
|
||||
final int priorityCategory = ALL_PRIORITY_CATEGORIES[i];
|
||||
if ((priorityCategories & priorityCategory) != 0) {
|
||||
if (sb.length() > 0) sb.append(',');
|
||||
sb.append(priorityCategoryToString(priorityCategory));
|
||||
}
|
||||
priorityCategories &= ~priorityCategory;
|
||||
}
|
||||
if (priorityCategories != 0) {
|
||||
if (sb.length() > 0) sb.append(',');
|
||||
sb.append("PRIORITY_CATEGORY_UNKNOWN_").append(priorityCategories);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String priorityCategoryToString(int priorityCategory) {
|
||||
switch (priorityCategory) {
|
||||
case PRIORITY_CATEGORY_REMINDERS: return "PRIORITY_CATEGORY_REMINDERS";
|
||||
case PRIORITY_CATEGORY_EVENTS: return "PRIORITY_CATEGORY_EVENTS";
|
||||
case PRIORITY_CATEGORY_MESSAGES: return "PRIORITY_CATEGORY_MESSAGES";
|
||||
case PRIORITY_CATEGORY_CALLS: return "PRIORITY_CATEGORY_CALLS";
|
||||
case PRIORITY_CATEGORY_REPEAT_CALLERS: return "PRIORITY_CATEGORY_REPEAT_CALLERS";
|
||||
default: return "PRIORITY_CATEGORY_UNKNOWN_" + priorityCategory;
|
||||
}
|
||||
}
|
||||
|
||||
public static String prioritySendersToString(int prioritySenders) {
|
||||
switch (prioritySenders) {
|
||||
case PRIORITY_SENDERS_ANY: return "PRIORITY_SENDERS_ANY";
|
||||
case PRIORITY_SENDERS_CONTACTS: return "PRIORITY_SENDERS_CONTACTS";
|
||||
case PRIORITY_SENDERS_STARRED: return "PRIORITY_SENDERS_STARRED";
|
||||
default: return "PRIORITY_SENDERS_UNKNOWN_" + prioritySenders;
|
||||
}
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<Policy> CREATOR = new Parcelable.Creator<Policy>() {
|
||||
@Override
|
||||
public Policy createFromParcel(Parcel in) {
|
||||
return new Policy(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy[] newArray(int size) {
|
||||
return new Policy[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +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.Service;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -500,6 +501,22 @@ 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}.
|
||||
*
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.service.notification;
|
||||
|
||||
import android.app.NotificationManager.Policy;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
@@ -470,6 +471,59 @@ public class ZenModeConfig implements Parcelable {
|
||||
}
|
||||
};
|
||||
|
||||
public Policy toNotificationPolicy() {
|
||||
int priorityCategories = 0;
|
||||
int prioritySenders = Policy.PRIORITY_SENDERS_ANY;
|
||||
if (allowCalls) {
|
||||
priorityCategories |= Policy.PRIORITY_CATEGORY_CALLS;
|
||||
}
|
||||
if (allowMessages) {
|
||||
priorityCategories |= Policy.PRIORITY_CATEGORY_MESSAGES;
|
||||
}
|
||||
if (allowEvents) {
|
||||
priorityCategories |= Policy.PRIORITY_CATEGORY_EVENTS;
|
||||
}
|
||||
if (allowReminders) {
|
||||
priorityCategories |= Policy.PRIORITY_CATEGORY_REMINDERS;
|
||||
}
|
||||
if (allowRepeatCallers) {
|
||||
priorityCategories |= Policy.PRIORITY_CATEGORY_REPEAT_CALLERS;
|
||||
}
|
||||
switch (allowFrom) {
|
||||
case SOURCE_ANYONE:
|
||||
prioritySenders = Policy.PRIORITY_SENDERS_ANY;
|
||||
break;
|
||||
case SOURCE_CONTACT:
|
||||
prioritySenders = Policy.PRIORITY_SENDERS_CONTACTS;
|
||||
break;
|
||||
case SOURCE_STAR:
|
||||
prioritySenders = Policy.PRIORITY_SENDERS_STARRED;
|
||||
break;
|
||||
}
|
||||
return new Policy(priorityCategories, prioritySenders);
|
||||
}
|
||||
|
||||
public void applyNotificationPolicy(Policy policy) {
|
||||
if (policy == null) return;
|
||||
allowCalls = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_CALLS) != 0;
|
||||
allowMessages = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_MESSAGES) != 0;
|
||||
allowEvents = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_EVENTS) != 0;
|
||||
allowReminders = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_REMINDERS) != 0;
|
||||
allowRepeatCallers = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_REPEAT_CALLERS)
|
||||
!= 0;
|
||||
switch (policy.prioritySenders) {
|
||||
case Policy.PRIORITY_SENDERS_CONTACTS:
|
||||
allowFrom = SOURCE_CONTACT;
|
||||
break;
|
||||
case Policy.PRIORITY_SENDERS_STARRED:
|
||||
allowFrom = SOURCE_STAR;
|
||||
break;
|
||||
default:
|
||||
allowFrom = SOURCE_ANYONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static Condition toTimeCondition(Context context, int minutesFromNow, int userHandle) {
|
||||
final long now = System.currentTimeMillis();
|
||||
final long millis = minutesFromNow == 0 ? ZERO_VALUE_MS : minutesFromNow * MINUTES_MS;
|
||||
@@ -881,4 +935,5 @@ public class ZenModeConfig implements Parcelable {
|
||||
public interface Migration {
|
||||
ZenModeConfig migrate(XmlV1 v1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,9 +29,11 @@ import android.app.AppGlobals;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.IActivityManager;
|
||||
import android.app.INotificationManager;
|
||||
import android.app.INotificationManagerCallback;
|
||||
import android.app.ITransientNotification;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.NotificationManager.Policy;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.StatusBarManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
@@ -227,6 +229,8 @@ 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<>();
|
||||
|
||||
|
||||
// The last key in this list owns the hardware.
|
||||
ArrayList<String> mLights = new ArrayList<>();
|
||||
@@ -893,6 +897,13 @@ public class NotificationManagerService extends SystemService {
|
||||
updateInterruptionFilterLocked();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void onPolicyChanged() {
|
||||
getContext().sendBroadcast(
|
||||
new Intent(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED)
|
||||
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY));
|
||||
}
|
||||
});
|
||||
final File systemDir = new File(Environment.getDataDirectory(), "system");
|
||||
mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
|
||||
@@ -1551,6 +1562,18 @@ 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 boolean checkPolicyToken(Policy.Token token) {
|
||||
return mPolicyTokens.containsValue(token)
|
||||
|| mListeners.mPolicyTokens.containsValue(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
|
||||
@@ -1586,24 +1609,73 @@ public class NotificationManagerService extends SystemService {
|
||||
enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled");
|
||||
return mConditionProviders.isSystemProviderEnabled(path);
|
||||
}
|
||||
};
|
||||
|
||||
private String[] getActiveNotificationKeys(INotificationListener token) {
|
||||
final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
|
||||
final ArrayList<String> keys = new ArrayList<String>();
|
||||
if (info.isEnabledForCurrentProfiles()) {
|
||||
synchronized (mNotificationList) {
|
||||
final int N = mNotificationList.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
final StatusBarNotification sbn = mNotificationList.get(i).sbn;
|
||||
if (info.enabledAndUserMatches(sbn.getUserId())) {
|
||||
keys.add(sbn.getKey());
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Policy.Token getPolicyTokenFromListener(INotificationListener listener) {
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return mListeners.getPolicyToken(listener);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
return keys.toArray(new String[keys.size()]);
|
||||
}
|
||||
|
||||
@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;
|
||||
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);
|
||||
}
|
||||
if (DBG) Slog.w(TAG, "requestNotificationPolicyToken granted for " + pkg);
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
callback.onPolicyToken(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNotificationPolicyTokenValid(String pkg, Policy.Token token) {
|
||||
return checkPolicyToken(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy getNotificationPolicy(Policy.Token token) {
|
||||
enforcePolicyToken(token, "getNotificationPolicy");
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return mZenModeHelper.getNotificationPolicy();
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNotificationPolicy(Policy.Token token, Policy policy) {
|
||||
enforcePolicyToken(token, "setNotificationPolicy");
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mZenModeHelper.setNotificationPolicy(policy);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private String disableNotificationEffects(NotificationRecord record) {
|
||||
if (mDisableNotificationEffects) {
|
||||
@@ -1718,6 +1790,10 @@ 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 Condition providers:");
|
||||
@@ -2970,12 +3046,18 @@ 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();
|
||||
@@ -3000,6 +3082,7 @@ public class NotificationManagerService extends SystemService {
|
||||
synchronized (mNotificationList) {
|
||||
updateNotificationGroupsDesiredLocked();
|
||||
update = makeRankingUpdateLocked(info);
|
||||
mPolicyTokens.put(info.component, new Policy.Token(new Binder()));
|
||||
}
|
||||
try {
|
||||
listener.onListenerConnected(update);
|
||||
@@ -3016,6 +3099,7 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
mLightTrimListeners.remove(removed);
|
||||
updateNotificationGroupsDesiredLocked();
|
||||
mPolicyTokens.remove(removed.component);
|
||||
}
|
||||
|
||||
public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import static android.media.AudioAttributes.USAGE_NOTIFICATION;
|
||||
import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.NotificationManager.Policy;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
@@ -57,6 +58,7 @@ import org.xmlpull.v1.XmlSerializer;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* NotificationManagerService helper for functionality related to zen mode.
|
||||
@@ -230,6 +232,21 @@ public class ZenModeHelper {
|
||||
mConfig.writeXml(out);
|
||||
}
|
||||
|
||||
public Policy getNotificationPolicy() {
|
||||
return getNotificationPolicy(mConfig);
|
||||
}
|
||||
|
||||
private static Policy getNotificationPolicy(ZenModeConfig config) {
|
||||
return config == null ? null : config.toNotificationPolicy();
|
||||
}
|
||||
|
||||
public void setNotificationPolicy(Policy policy) {
|
||||
if (policy == null || mConfig == null) return;
|
||||
final ZenModeConfig newConfig = mConfig.copy();
|
||||
newConfig.applyNotificationPolicy(policy);
|
||||
setConfig(newConfig, "setNotificationPolicy");
|
||||
}
|
||||
|
||||
public ZenModeConfig getConfig() {
|
||||
return mConfig;
|
||||
}
|
||||
@@ -247,8 +264,13 @@ public class ZenModeHelper {
|
||||
if (config.equals(mConfig)) return true;
|
||||
if (DEBUG) Log.d(TAG, "setConfig reason=" + reason);
|
||||
ZenLog.traceConfig(mConfig, config);
|
||||
final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
|
||||
getNotificationPolicy(config));
|
||||
mConfig = config;
|
||||
dispatchOnConfigChanged();
|
||||
if (policyChanged){
|
||||
dispatchOnPolicyChanged();
|
||||
}
|
||||
final String val = Integer.toString(mConfig.hashCode());
|
||||
Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
|
||||
if (!evaluateZenMode(reason, setRingerMode)) {
|
||||
@@ -355,6 +377,12 @@ public class ZenModeHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchOnPolicyChanged() {
|
||||
for (Callback callback : mCallbacks) {
|
||||
callback.onPolicyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchOnZenModeChanged() {
|
||||
for (Callback callback : mCallbacks) {
|
||||
callback.onZenModeChanged();
|
||||
@@ -617,6 +645,7 @@ public class ZenModeHelper {
|
||||
public static class Callback {
|
||||
void onConfigChanged() {}
|
||||
void onZenModeChanged() {}
|
||||
void onPolicyChanged() {}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user