CTS tests for notif delegate notif canceling

Test: this
Bug: 134585713
Change-Id: If24af43392c873e3807bb38f1e0ac4cfa467eec9
diff --git a/tests/app/NotificationDelegator/AndroidManifest.xml b/tests/app/NotificationDelegator/AndroidManifest.xml
index 54d1f05..fbdf219 100644
--- a/tests/app/NotificationDelegator/AndroidManifest.xml
+++ b/tests/app/NotificationDelegator/AndroidManifest.xml
@@ -30,5 +30,13 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
+
+        <activity android:name="com.android.test.notificationdelegator.NotificationDelegateAndPost">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
     </application>
 </manifest>
diff --git a/tests/app/NotificationDelegator/src/com/android/test/notificationdelegator/NotificationDelegateAndPost.java b/tests/app/NotificationDelegator/src/com/android/test/notificationdelegator/NotificationDelegateAndPost.java
new file mode 100644
index 0000000..521adc5
--- /dev/null
+++ b/tests/app/NotificationDelegator/src/com/android/test/notificationdelegator/NotificationDelegateAndPost.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 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 com.android.test.notificationdelegator;
+
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+
+import android.app.Activity;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.os.Bundle;
+import android.util.Log;
+
+public class NotificationDelegateAndPost extends Activity {
+    private static final String TAG = "DelegateAndPost";
+    private static final String DELEGATE = "android.app.stubs";
+    private static final String CHANNEL = "channel";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity);
+
+        NotificationManager nm = getSystemService(NotificationManager.class);
+
+        nm.createNotificationChannel(new NotificationChannel(CHANNEL, CHANNEL, IMPORTANCE_LOW));
+        nm.setNotificationDelegate(DELEGATE);
+        Log.d(TAG, "Set delegate: " + nm.getNotificationDelegate());
+
+        Log.d(TAG, "Posting notification with id 9");
+
+        Notification n = new Notification.Builder(this, CHANNEL)
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setContentTitle("posted by delegator")
+                .build();
+
+        nm.notify(9, n);
+
+        finish();
+    }
+}
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index 2f9658a..5c49b68 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -91,9 +91,6 @@
 import android.util.Log;
 import android.widget.RemoteViews;
 
-import androidx.test.filters.FlakyTest;
-import androidx.test.InstrumentationRegistry;
-
 import com.android.compatibility.common.util.SystemUtil;
 
 import junit.framework.Assert;
@@ -111,6 +108,9 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
+
 /* This tests NotificationListenerService together with NotificationManager, as you need to have
  * notifications to manipulate in order to test the listener service. */
 public class NotificationManagerTest extends AndroidTestCase {
@@ -119,6 +119,7 @@
     final String NOTIFICATION_CHANNEL_ID = "NotificationManagerTest";
 
     private static final String DELEGATOR = "com.android.test.notificationdelegator";
+    private static final String DELEGATE_POST_CLASS = DELEGATOR + ".NotificationDelegateAndPost";
     private static final String REVOKE_CLASS = DELEGATOR + ".NotificationRevoker";
     private static final int WAIT_TIME = 2000;
 
@@ -257,14 +258,13 @@
         return null;
     }
 
-
-    private StatusBarNotification findPostedNotification(int id) {
+    private StatusBarNotification findPostedNotification(int id, boolean all) {
         // notification is a bit asynchronous so it may take a few ms to appear in
         // getActiveNotifications()
         // we will check for it for up to 300ms before giving up
         StatusBarNotification n = null;
         for (int tries = 3; tries-- > 0; ) {
-            final StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
+            final StatusBarNotification[] sbns = getActiveNotifications(all);
             for (StatusBarNotification sbn : sbns) {
                 Log.d(TAG, "Found " + sbn.getKey());
                 if (sbn.getId() == id) {
@@ -282,6 +282,14 @@
         return n;
     }
 
+    private StatusBarNotification[] getActiveNotifications(boolean all) {
+        if (all) {
+            return mListener.getActiveNotifications();
+        } else {
+            return mNotificationManager.getActiveNotifications();
+        }
+    }
+
     private PendingIntent getPendingIntent() {
         return PendingIntent.getActivity(
                 getContext(), 0, new Intent(getContext(), this.getClass()), 0);
@@ -1287,7 +1295,7 @@
         NotificationListenerService.Ranking outRanking =
                 new NotificationListenerService.Ranking();
 
-        StatusBarNotification sbn = findPostedNotification(notificationId);
+        StatusBarNotification sbn = findPostedNotification(notificationId, false);
 
         // check that the key and channel ids are the same in the ranking as the posted notification
         for (String key : rankingMap.getOrderedKeys()) {
@@ -1931,7 +1939,7 @@
                         .build();
         mNotificationManager.notify(id, notification);
 
-        StatusBarNotification n = findPostedNotification(id);
+        StatusBarNotification n = findPostedNotification(id, false);
         assertNotNull(n);
         assertEquals(notification.fullScreenIntent, n.getNotification().fullScreenIntent);
     }
@@ -1985,7 +1993,77 @@
                 .build();
         mNotificationManager.notifyAsPackage(DELEGATOR, "tag", 0, n);
 
-        findPostedNotification(0);
+        assertNotNull(findPostedNotification(0, false));
+
+        final Intent revokeIntent = new Intent();
+        revokeIntent.setClassName(DELEGATOR, REVOKE_CLASS);
+        revokeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(revokeIntent);
+        Thread.sleep(1000);
+    }
+
+    public void testNotificationDelegate_grantAndPostAndCancel() throws Exception {
+        // grant this test permission to post
+        final Intent activityIntent = new Intent();
+        activityIntent.setPackage(DELEGATOR);
+        activityIntent.setAction(Intent.ACTION_MAIN);
+        activityIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+        activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        // wait for the activity to launch and finish
+        mContext.startActivity(activityIntent);
+        Thread.sleep(1000);
+
+        // send notification
+        Notification n = new Notification.Builder(mContext, "channel")
+                .setSmallIcon(android.R.id.icon)
+                .build();
+        mNotificationManager.notifyAsPackage(DELEGATOR, "toBeCanceled", 10000, n);
+
+        assertNotNull(findPostedNotification(10000, false));
+
+        mNotificationManager.cancelAsPackage(DELEGATOR, "toBeCanceled", 10000);
+
+        assertNull(findPostedNotification(10000, false));
+
+        final Intent revokeIntent = new Intent();
+        revokeIntent.setClassName(DELEGATOR, REVOKE_CLASS);
+        revokeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(revokeIntent);
+        Thread.sleep(1000);
+    }
+
+    public void testNotificationDelegate_cannotCancelNotificationsPostedByDelegator()
+            throws Exception {
+        if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
+            return;
+        }
+
+        toggleListenerAccess(TestNotificationListener.getId(),
+                InstrumentationRegistry.getInstrumentation(), true);
+        Thread.sleep(500); // wait for listener to be allowed
+
+        mListener = TestNotificationListener.getInstance();
+        assertNotNull(mListener);
+
+        // grant this test permission to post
+        final Intent activityIntent = new Intent();
+        activityIntent.setClassName(DELEGATOR, DELEGATE_POST_CLASS);
+        activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        mContext.startActivity(activityIntent);
+
+        assertNotNull(findPostedNotification(9, true));
+
+        try {
+            mNotificationManager.cancelAsPackage(DELEGATOR, null, 9);
+            fail ("Delegate should not be able to cancel notification they did not post");
+        } catch (SecurityException e) {
+            // yay
+        }
+
+        // double check that the notification does still exist
+        assertNotNull(findPostedNotification(9, true));
 
         final Intent revokeIntent = new Intent();
         revokeIntent.setClassName(DELEGATOR, REVOKE_CLASS);
@@ -2104,7 +2182,7 @@
                         .build();
         mNotificationManager.notify(id, notification);
 
-        StatusBarNotification n = findPostedNotification(id);
+        StatusBarNotification n = findPostedNotification(id, false);
         assertNotNull(n);
     }
 
@@ -2199,8 +2277,8 @@
         sendNotification(notificationId2, R.drawable.black);
         Thread.sleep(500); // wait for notification listener to receive notification
 
-        StatusBarNotification sbn1 = findPostedNotification(notificationId1);
-        StatusBarNotification sbn2 = findPostedNotification(notificationId2);
+        StatusBarNotification sbn1 = findPostedNotification(notificationId1, false);
+        StatusBarNotification sbn2 = findPostedNotification(notificationId2, false);
         mListener.setNotificationsShown(new String[]{ sbn1.getKey() });
 
         toggleListenerAccess(TestNotificationListener.getId(),
@@ -2296,8 +2374,8 @@
         sendNotification(notificationId2, R.drawable.black);
         Thread.sleep(500); // wait for notification listener to receive notification
 
-        StatusBarNotification sbn1 = findPostedNotification(notificationId1);
-        StatusBarNotification sbn2 = findPostedNotification(notificationId2);
+        StatusBarNotification sbn1 = findPostedNotification(notificationId1, false);
+        StatusBarNotification sbn2 = findPostedNotification(notificationId2, false);
         StatusBarNotification[] notifs =
                 mListener.getActiveNotifications(new String[]{ sbn2.getKey(), sbn1.getKey() });
         assertEquals(sbn2.getKey(), notifs[0].getKey());
@@ -2345,7 +2423,7 @@
         sendNotification(notificationId, R.drawable.black);
         Thread.sleep(500); // wait for notification listener to receive notification
 
-        StatusBarNotification sbn = findPostedNotification(notificationId);
+        StatusBarNotification sbn = findPostedNotification(notificationId, false);
 
         mListener.cancelNotification(sbn.getPackageName(), sbn.getTag(), sbn.getId());
         if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {