API changes for NAS
- make NAS @SystemApi and guard with permission
- Add missing Nullable/NonNull annotations
Fixes: 126699678
Fixes: 127146476
Test: make, gts
Change-Id: Ie024983f7c440d5b4d3065af031b27958395f2f1
diff --git a/api/current.txt b/api/current.txt
index efd2170..d6b5bc83 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5810,7 +5810,6 @@
method public java.util.List<android.app.NotificationChannel> getNotificationChannels();
method @Nullable public String getNotificationDelegate();
method public android.app.NotificationManager.Policy getNotificationPolicy();
- method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
method public boolean isNotificationListenerAccessGranted(android.content.ComponentName);
method public boolean isNotificationPolicyAccessGranted();
method public void notify(int, android.app.Notification);
@@ -41600,23 +41599,6 @@
package android.service.notification {
- public final class Adjustment implements android.os.Parcelable {
- ctor public Adjustment(@NonNull String, @NonNull String, @NonNull android.os.Bundle, @NonNull CharSequence, @NonNull android.os.UserHandle);
- method public int describeContents();
- method @NonNull public CharSequence getExplanation();
- method @NonNull public String getKey();
- method @NonNull public String getPackage();
- method @NonNull public android.os.Bundle getSignals();
- method @NonNull public android.os.UserHandle getUserHandle();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR;
- field public static final String KEY_CONTEXTUAL_ACTIONS = "key_contextual_actions";
- field public static final String KEY_IMPORTANCE = "key_importance";
- field public static final String KEY_SNOOZE_CRITERIA = "key_snooze_criteria";
- field public static final String KEY_TEXT_REPLIES = "key_text_replies";
- field public static final String KEY_USER_SENTIMENT = "key_user_sentiment";
- }
-
public final class Condition implements android.os.Parcelable {
ctor public Condition(android.net.Uri, String, int);
ctor public Condition(android.net.Uri, String, String, String, int, int, int);
@@ -41663,26 +41645,6 @@
field @Deprecated public static final String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
}
- public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
- ctor public NotificationAssistantService();
- method public final void adjustNotification(@NonNull android.service.notification.Adjustment);
- method public final void adjustNotifications(@NonNull java.util.List<android.service.notification.Adjustment>);
- method public void onActionInvoked(@NonNull String, @NonNull android.app.Notification.Action, int);
- method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
- method public void onNotificationDirectReplied(@NonNull String);
- method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification);
- method @Nullable public android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification, @NonNull android.app.NotificationChannel);
- method public void onNotificationExpansionChanged(@NonNull String, boolean, boolean);
- method public void onNotificationRemoved(@NonNull android.service.notification.StatusBarNotification, @NonNull android.service.notification.NotificationListenerService.RankingMap, @NonNull android.service.notification.NotificationStats, int);
- method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, String);
- method public void onNotificationsSeen(@NonNull java.util.List<java.lang.String>);
- method public void onSuggestedReplySent(@NonNull String, @NonNull CharSequence, int);
- method public final void unsnoozeNotification(String);
- field public static final String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
- field public static final int SOURCE_FROM_APP = 0; // 0x0
- field public static final int SOURCE_FROM_ASSISTANT = 1; // 0x1
- }
-
public abstract class NotificationListenerService extends android.app.Service {
ctor public NotificationListenerService();
method public final void cancelAllNotifications();
@@ -41785,37 +41747,6 @@
field @NonNull public static final android.os.Parcelable.Creator<android.service.notification.NotificationListenerService.RankingMap> CREATOR;
}
- public final class NotificationStats implements android.os.Parcelable {
- ctor public NotificationStats();
- method public int describeContents();
- method public int getDismissalSentiment();
- method public int getDismissalSurface();
- method public boolean hasDirectReplied();
- method public boolean hasExpanded();
- method public boolean hasInteracted();
- method public boolean hasSeen();
- method public boolean hasSnoozed();
- method public boolean hasViewedSettings();
- method public void setDirectReplied();
- method public void setDismissalSentiment(int);
- method public void setDismissalSurface(int);
- method public void setExpanded();
- method public void setSeen();
- method public void setSnoozed();
- method public void setViewedSettings();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.service.notification.NotificationStats> CREATOR;
- field public static final int DISMISSAL_AOD = 2; // 0x2
- field public static final int DISMISSAL_NOT_DISMISSED = -1; // 0xffffffff
- field public static final int DISMISSAL_OTHER = 0; // 0x0
- field public static final int DISMISSAL_PEEK = 1; // 0x1
- field public static final int DISMISSAL_SHADE = 3; // 0x3
- field public static final int DISMISS_SENTIMENT_NEGATIVE = 0; // 0x0
- field public static final int DISMISS_SENTIMENT_NEUTRAL = 1; // 0x1
- field public static final int DISMISS_SENTIMENT_POSITIVE = 2; // 0x2
- field public static final int DISMISS_SENTIMENT_UNKNOWN = -1000; // 0xfffffc18
- }
-
public class StatusBarNotification implements android.os.Parcelable {
ctor @Deprecated public StatusBarNotification(String, String, int, String, int, int, int, android.app.Notification, android.os.UserHandle, long);
ctor public StatusBarNotification(android.os.Parcel);
diff --git a/api/system-current.txt b/api/system-current.txt
index b646db3..e949988 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -161,6 +161,7 @@
field public static final String REMOTE_DISPLAY_PROVIDER = "android.permission.REMOTE_DISPLAY_PROVIDER";
field public static final String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES";
field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
+ field public static final String REQUEST_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE";
field public static final String RESET_PASSWORD = "android.permission.RESET_PASSWORD";
field public static final String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS";
field public static final String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
@@ -547,6 +548,7 @@
public class NotificationManager {
method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
method @Nullable public android.content.ComponentName getAllowedNotificationAssistantForUser(android.os.UserHandle);
+ method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
method public void setNotificationAssistantAccessGranted(android.content.ComponentName, boolean);
method public void setNotificationAssistantAccessGrantedForUser(android.content.ComponentName, android.os.UserHandle, boolean);
}
@@ -6619,13 +6621,78 @@
public final class Adjustment implements android.os.Parcelable {
ctor public Adjustment(String, String, android.os.Bundle, CharSequence, int);
+ ctor public Adjustment(@NonNull String, @NonNull String, @NonNull android.os.Bundle, @NonNull CharSequence, @NonNull android.os.UserHandle);
ctor protected Adjustment(android.os.Parcel);
+ method public int describeContents();
+ method @NonNull public CharSequence getExplanation();
+ method @NonNull public String getKey();
+ method @NonNull public String getPackage();
+ method @NonNull public android.os.Bundle getSignals();
method public int getUser();
+ method @NonNull public android.os.UserHandle getUserHandle();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR;
+ field public static final String KEY_CONTEXTUAL_ACTIONS = "key_contextual_actions";
+ field public static final String KEY_IMPORTANCE = "key_importance";
field public static final String KEY_PEOPLE = "key_people";
+ field public static final String KEY_SNOOZE_CRITERIA = "key_snooze_criteria";
+ field public static final String KEY_TEXT_REPLIES = "key_text_replies";
+ field public static final String KEY_USER_SENTIMENT = "key_user_sentiment";
+ }
+
+ public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
+ ctor public NotificationAssistantService();
+ method public final void adjustNotification(@NonNull android.service.notification.Adjustment);
+ method public final void adjustNotifications(@NonNull java.util.List<android.service.notification.Adjustment>);
+ method public void onActionInvoked(@NonNull String, @NonNull android.app.Notification.Action, int);
+ method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
+ method public void onNotificationDirectReplied(@NonNull String);
+ method @Nullable public abstract android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification);
+ method @Nullable public android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification, @NonNull android.app.NotificationChannel);
+ method public void onNotificationExpansionChanged(@NonNull String, boolean, boolean);
+ method public abstract void onNotificationSnoozedUntilContext(@NonNull android.service.notification.StatusBarNotification, @NonNull String);
+ method public void onNotificationsSeen(@NonNull java.util.List<java.lang.String>);
+ method public void onSuggestedReplySent(@NonNull String, @NonNull CharSequence, int);
+ method public final void unsnoozeNotification(@NonNull String);
+ field public static final String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
+ field public static final int SOURCE_FROM_APP = 0; // 0x0
+ field public static final int SOURCE_FROM_ASSISTANT = 1; // 0x1
+ }
+
+ public abstract class NotificationListenerService extends android.app.Service {
+ method public void onNotificationRemoved(@NonNull android.service.notification.StatusBarNotification, @NonNull android.service.notification.NotificationListenerService.RankingMap, @NonNull android.service.notification.NotificationStats, int);
}
public final class NotificationStats implements android.os.Parcelable {
+ ctor public NotificationStats();
ctor protected NotificationStats(android.os.Parcel);
+ method public int describeContents();
+ method public int getDismissalSentiment();
+ method public int getDismissalSurface();
+ method public boolean hasDirectReplied();
+ method public boolean hasExpanded();
+ method public boolean hasInteracted();
+ method public boolean hasSeen();
+ method public boolean hasSnoozed();
+ method public boolean hasViewedSettings();
+ method public void setDirectReplied();
+ method public void setDismissalSentiment(int);
+ method public void setDismissalSurface(int);
+ method public void setExpanded();
+ method public void setSeen();
+ method public void setSnoozed();
+ method public void setViewedSettings();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.notification.NotificationStats> CREATOR;
+ field public static final int DISMISSAL_AOD = 2; // 0x2
+ field public static final int DISMISSAL_NOT_DISMISSED = -1; // 0xffffffff
+ field public static final int DISMISSAL_OTHER = 0; // 0x0
+ field public static final int DISMISSAL_PEEK = 1; // 0x1
+ field public static final int DISMISSAL_SHADE = 3; // 0x3
+ field public static final int DISMISS_SENTIMENT_NEGATIVE = 0; // 0x0
+ field public static final int DISMISS_SENTIMENT_NEUTRAL = 1; // 0x1
+ field public static final int DISMISS_SENTIMENT_POSITIVE = 2; // 0x2
+ field public static final int DISMISS_SENTIMENT_UNKNOWN = -1000; // 0xfffffc18
}
public final class SnoozeCriterion implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index bafd1d5..5a8afe3 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2320,7 +2320,38 @@
}
public abstract class NotificationListenerService extends android.app.Service {
- method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, android.service.notification.NotificationStats, int);
+ method public void onNotificationRemoved(@NonNull android.service.notification.StatusBarNotification, @NonNull android.service.notification.NotificationListenerService.RankingMap, @NonNull android.service.notification.NotificationStats, int);
+ }
+
+ public final class NotificationStats implements android.os.Parcelable {
+ ctor public NotificationStats();
+ method public int describeContents();
+ method public int getDismissalSentiment();
+ method public int getDismissalSurface();
+ method public boolean hasDirectReplied();
+ method public boolean hasExpanded();
+ method public boolean hasInteracted();
+ method public boolean hasSeen();
+ method public boolean hasSnoozed();
+ method public boolean hasViewedSettings();
+ method public void setDirectReplied();
+ method public void setDismissalSentiment(int);
+ method public void setDismissalSurface(int);
+ method public void setExpanded();
+ method public void setSeen();
+ method public void setSnoozed();
+ method public void setViewedSettings();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.notification.NotificationStats> CREATOR;
+ field public static final int DISMISSAL_AOD = 2; // 0x2
+ field public static final int DISMISSAL_NOT_DISMISSED = -1; // 0xffffffff
+ field public static final int DISMISSAL_OTHER = 0; // 0x0
+ field public static final int DISMISSAL_PEEK = 1; // 0x1
+ field public static final int DISMISSAL_SHADE = 3; // 0x3
+ field public static final int DISMISS_SENTIMENT_NEGATIVE = 0; // 0x0
+ field public static final int DISMISS_SENTIMENT_NEUTRAL = 1; // 0x1
+ field public static final int DISMISS_SENTIMENT_POSITIVE = 2; // 0x2
+ field public static final int DISMISS_SENTIMENT_UNKNOWN = -1000; // 0xfffffc18
}
public final class SnoozeCriterion implements android.os.Parcelable {
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 6ad6e38..edf86f9 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1168,7 +1168,9 @@
* matches the system intent action
* TODO: STOPSHIP: Add correct intent
* {@link android.provider.Settings#ACTION_MANAGE_DEFAULT_APPS_SETTINGS}.
+ * @hide
*/
+ @SystemApi
public boolean isNotificationAssistantAccessGranted(@NonNull ComponentName assistant) {
INotificationManager service = getService();
try {
diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java
index af0dfd2..1cdb62f 100644
--- a/core/java/android/service/notification/Adjustment.java
+++ b/core/java/android/service/notification/Adjustment.java
@@ -32,7 +32,10 @@
* realizes on the notification rankings.
*
* Notifications affected by the Adjustment will be re-ranked if necessary.
+ *
+ * @hide
*/
+@SystemApi
public final class Adjustment implements Parcelable {
private final String mPackage;
private final String mKey;
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index ceb21e7..87bdfe0 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -22,6 +22,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.admin.DevicePolicyManager;
@@ -60,7 +61,9 @@
* <p>
* All callbacks are called on the main thread.
* </p>
+ * @hide
*/
+@SystemApi
public abstract class NotificationAssistantService extends NotificationListenerService {
private static final String TAG = "NotificationAssistants";
@@ -112,8 +115,8 @@
* @param sbn the notification to snooze
* @param snoozeCriterionId the {@link SnoozeCriterion#getId()} representing a device context.
*/
- abstract public void onNotificationSnoozedUntilContext(StatusBarNotification sbn,
- String snoozeCriterionId);
+ abstract public void onNotificationSnoozedUntilContext(@NonNull StatusBarNotification sbn,
+ @NonNull String snoozeCriterionId);
/**
* A notification was posted by an app. Called before post.
@@ -124,7 +127,7 @@
* @param sbn the new notification
* @return an adjustment or null to take no action, within 100ms.
*/
- abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn);
+ abstract public @Nullable Adjustment onNotificationEnqueued(@NonNull StatusBarNotification sbn);
/**
* A notification was posted by an app. Called before post.
@@ -255,7 +258,7 @@
* notification.
* @param key The key of the notification to snooze
*/
- public final void unsnoozeNotification(String key) {
+ public final void unsnoozeNotification(@NonNull String key) {
if (!isBound()) return;
try {
getNotificationInterface().unsnoozeNotificationFromAssistant(mWrapper, key);
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 767a3f7..23607eb 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -425,8 +425,9 @@
* @hide
*/
@TestApi
- public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap,
- NotificationStats stats, int reason) {
+ @SystemApi
+ public void onNotificationRemoved(@NonNull StatusBarNotification sbn,
+ @NonNull RankingMap rankingMap, @NonNull NotificationStats stats, int reason) {
onNotificationRemoved(sbn, rankingMap, reason);
}
diff --git a/core/java/android/service/notification/NotificationStats.java b/core/java/android/service/notification/NotificationStats.java
index 5a54a43..2b4c24c 100644
--- a/core/java/android/service/notification/NotificationStats.java
+++ b/core/java/android/service/notification/NotificationStats.java
@@ -17,6 +17,7 @@
import android.annotation.IntDef;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.app.RemoteInput;
import android.os.Parcel;
import android.os.Parcelable;
@@ -24,6 +25,12 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+/**
+ * Information about how the user has interacted with a given notification.
+ * @hide
+ */
+@TestApi
+@SystemApi
public final class NotificationStats implements Parcelable {
private boolean mSeen;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4c4393d..9aaa14f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3966,6 +3966,13 @@
<permission android:name="android.permission.UPDATE_LOCK"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an application the opportunity to become a
+ {@link android.service.notification.NotificationAssistantService}.
+ User permission is still required before access is granted.
+ @hide -->
+ <permission android:name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi @TestApi Allows an application to read the current set of notifications, including
any metadata and intents attached.
@hide -->
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index f19e44c..fcd5d56 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -23,6 +23,7 @@
<privapp-permissions package="android.ext.services">
<permission name="android.permission.PROVIDE_RESOLVER_RANKER_SERVICE" />
<permission name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE" />
+ <permission name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" />
</privapp-permissions>
<privapp-permissions package="com.android.apps.tag">
diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml
index fe6581b..48c72ba 100644
--- a/packages/ExtServices/AndroidManifest.xml
+++ b/packages/ExtServices/AndroidManifest.xml
@@ -25,6 +25,7 @@
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<uses-permission android:name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE" />
+ <uses-permission android:name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" />
<application android:label="@string/app_name"
android:defaultToDeviceProtectedStorage="true"
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 41f2cc5..64477a5 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -192,6 +192,11 @@
return true;
}
+ @Override
+ protected String getRequiredPermission() {
+ return null;
+ }
+
public ManagedServiceInfo checkServiceToken(IConditionProvider provider) {
synchronized(mMutex) {
return checkServiceTokenLocked(provider);
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 8480830..7a87a57 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -64,6 +64,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.XmlUtils;
+import com.android.internal.util.function.TriPredicate;
import com.android.server.notification.NotificationManagerService.DumpFilter;
import org.xmlpull.v1.XmlPullParser;
@@ -360,7 +361,7 @@
public void readXml(
XmlPullParser parser,
- Predicate<String> allowedManagedServicePackages,
+ TriPredicate<String, Integer, String> allowedManagedServicePackages,
boolean forRestore,
int userId)
throws XmlPullParserException, IOException {
@@ -383,8 +384,8 @@
final boolean isPrimary =
XmlUtils.readBooleanAttribute(parser, ATT_IS_PRIMARY, true);
readExtraAttributes(tag, parser, resolvedUserId);
- if (allowedManagedServicePackages == null ||
- allowedManagedServicePackages.test(getPackageName(approved))) {
+ if (allowedManagedServicePackages == null || allowedManagedServicePackages.test(
+ getPackageName(approved), resolvedUserId, getRequiredPermission())) {
if (mUm.getUserInfo(resolvedUserId) != null) {
addApprovedList(approved, resolvedUserId, isPrimary);
}
@@ -402,6 +403,8 @@
protected void readExtraAttributes(String tag, XmlPullParser parser, int userId)
throws IOException {}
+ protected abstract String getRequiredPermission();
+
private void loadAllowedComponentsFromSettings() {
for (UserInfo user : mUm.getUsers()) {
final ContentResolver cr = mContext.getContentResolver();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 22f0b9db..9281bf8 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -205,6 +205,7 @@
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
+import com.android.internal.util.function.TriPredicate;
import com.android.server.DeviceIdleController;
import com.android.server.EventLogTags;
import com.android.server.IoThread;
@@ -432,7 +433,7 @@
private boolean mIsAutomotive;
private MetricsLogger mMetricsLogger;
- private Predicate<String> mAllowedManagedServicePackages;
+ private TriPredicate<String, Integer, String> mAllowedManagedServicePackages;
private static class Archive {
final int mBufferSize;
@@ -3614,7 +3615,8 @@
checkCallerIsSystemOrShell();
final long identity = Binder.clearCallingIdentity();
try {
- if (mAllowedManagedServicePackages.test(pkg)) {
+ if (mAllowedManagedServicePackages.test(
+ pkg, userId, mConditionProviders.getRequiredPermission())) {
mConditionProviders.setPackageOrComponentEnabled(
pkg, userId, true, granted);
@@ -3771,7 +3773,8 @@
checkCallerIsSystemOrShell();
final long identity = Binder.clearCallingIdentity();
try {
- if (mAllowedManagedServicePackages.test(listener.getPackageName())) {
+ if (mAllowedManagedServicePackages.test(
+ listener.getPackageName(), userId, mListeners.getRequiredPermission())) {
mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
userId, false, granted);
mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
@@ -4022,7 +4025,8 @@
}
return;
}
- if (mAllowedManagedServicePackages.test(assistant.getPackageName())) {
+ if (mAllowedManagedServicePackages.test(assistant.getPackageName(), userId,
+ mAssistants.getRequiredPermission())) {
mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
userId, false, granted);
mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
@@ -7084,7 +7088,7 @@
}
@VisibleForTesting
- boolean canUseManagedServices(String pkg) {
+ boolean canUseManagedServices(String pkg, Integer userId, String requiredPermission) {
boolean canUseManagedServices = !mActivityManager.isLowRamDevice()
|| mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_WATCH);
@@ -7095,6 +7099,17 @@
}
}
+ if (requiredPermission != null) {
+ try {
+ if (mPackageManager.checkPermission(requiredPermission, pkg, userId)
+ != PackageManager.PERMISSION_GRANTED) {
+ canUseManagedServices = false;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "can't talk to pm", e);
+ }
+ }
+
return canUseManagedServices;
}
@@ -7179,6 +7194,12 @@
rebindServices(true, user);
}
+ @Override
+ protected String getRequiredPermission() {
+ // only signature/privileged apps can be bound
+ return android.Manifest.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE;
+ }
+
protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
// There should be only one, but it's a list, so while we enforce
// singularity elsewhere, we keep it general here, to avoid surprises.
@@ -7486,6 +7507,11 @@
mLightTrimListeners.remove(removed);
}
+ @Override
+ protected String getRequiredPermission() {
+ return null;
+ }
+
@GuardedBy("mNotificationLock")
public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
if (trim == TRIM_LIGHT) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 7a530df..43fe674 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -1228,5 +1228,10 @@
protected void onServiceAdded(ManagedServiceInfo info) {
}
+
+ @Override
+ protected String getRequiredPermission() {
+ return null;
+ }
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 5df1941..7df52b2 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -3660,7 +3660,7 @@
.thenReturn(new String[] {"a", "b", "c"});
when(mContext.getResources()).thenReturn(mResources);
- assertEquals(false, mService.canUseManagedServices(null));
+ assertEquals(false, mService.canUseManagedServices(null, 0, null));
}
@Test
@@ -3671,7 +3671,7 @@
.thenReturn(new String[] {"a", "b", "c"});
when(mContext.getResources()).thenReturn(mResources);
- assertEquals(true, mService.canUseManagedServices("b"));
+ assertEquals(true, mService.canUseManagedServices("b", 0, null));
}
@Test
@@ -3682,7 +3682,7 @@
.thenReturn(new String[] {"a", "b", "c"});
when(mContext.getResources()).thenReturn(mResources);
- assertEquals(false, mService.canUseManagedServices("d"));
+ assertEquals(false, mService.canUseManagedServices("d", 0, null));
}
@Test
@@ -3693,7 +3693,7 @@
.thenReturn(new String[] {"a", "b", "c"});
when(mContext.getResources()).thenReturn(mResources);
- assertEquals(true, mService.canUseManagedServices("d"));
+ assertEquals(true, mService.canUseManagedServices("d", 0, null));
}
@Test
@@ -3704,7 +3704,7 @@
.thenReturn(new String[] {"a", "b", "c"});
when(mContext.getResources()).thenReturn(mResources);
- assertEquals(true, mService.canUseManagedServices("d"));
+ assertEquals(true, mService.canUseManagedServices("d", 0 , null));
}
@Test
@@ -3715,7 +3715,28 @@
.thenReturn(new String[] {"a", "b", "c"});
when(mContext.getResources()).thenReturn(mResources);
- assertEquals(true, mService.canUseManagedServices("d"));
+ assertEquals(true, mService.canUseManagedServices("d", 0, null));
+ }
+
+ @Test
+ public void testCanUseManagedServices_hasPermission() throws Exception {
+ when(mPackageManager.checkPermission("perm", "pkg", 0))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+ assertEquals(true, mService.canUseManagedServices("pkg", 0, "perm"));
+ }
+
+ @Test
+ public void testCanUseManagedServices_noPermission() throws Exception {
+ when(mPackageManager.checkPermission("perm", "pkg", 0))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+
+ assertEquals(false, mService.canUseManagedServices("pkg", 0, "perm"));
+ }
+
+ @Test
+ public void testCanUseManagedServices_permDoesNotMatter() {
+ assertEquals(true, mService.canUseManagedServices("pkg", 0, null));
}
@Test