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