1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.notification; 18 19 import static junit.framework.Assert.assertEquals; 20 import static junit.framework.Assert.assertFalse; 21 import static junit.framework.Assert.assertTrue; 22 23 import android.content.Context; 24 import android.content.Intent; 25 import android.provider.Settings; 26 import android.testing.AndroidTestingRunner; 27 28 import androidx.test.filters.SmallTest; 29 30 import com.android.server.UiServiceTestCase; 31 32 import org.junit.Before; 33 import org.junit.Test; 34 import org.junit.runner.RunWith; 35 36 @RunWith(AndroidTestingRunner.class) 37 @SmallTest 38 public class ReviewNotificationPermissionsReceiverTest extends UiServiceTestCase { 39 40 // Simple mock class that just overrides the reschedule and cancel behavior so that it's easy 41 // to tell whether the receiver has sent requests to either reschedule or cancel the 42 // notification (or both). 43 private class MockReviewNotificationPermissionsReceiver 44 extends ReviewNotificationPermissionsReceiver { 45 boolean mCanceled = false; 46 boolean mRescheduled = false; 47 48 @Override cancelNotification(Context context)49 protected void cancelNotification(Context context) { 50 mCanceled = true; 51 } 52 53 @Override rescheduleNotification(Context context)54 protected void rescheduleNotification(Context context) { 55 mRescheduled = true; 56 } 57 } 58 59 private MockReviewNotificationPermissionsReceiver mReceiver; 60 private Intent mIntent; 61 62 @Before setUp()63 public void setUp() { 64 mReceiver = new MockReviewNotificationPermissionsReceiver(); 65 mIntent = new Intent(); // actions will be set in test cases 66 } 67 68 @Test testReceive_remindMeLater_firstTime()69 public void testReceive_remindMeLater_firstTime() { 70 // Test what happens when we receive a "remind me later" intent coming from 71 // a previously-not-interacted notification 72 Settings.Global.putInt(mContext.getContentResolver(), 73 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 74 NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW); 75 76 // set up Intent action 77 mIntent.setAction(NotificationManagerService.REVIEW_NOTIF_ACTION_REMIND); 78 79 // Upon receipt of the intent, the following things should happen: 80 // - notification rescheduled 81 // - notification explicitly canceled 82 // - settings state updated to indicate user has interacted 83 mReceiver.onReceive(mContext, mIntent); 84 assertTrue(mReceiver.mRescheduled); 85 assertTrue(mReceiver.mCanceled); 86 assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_USER_INTERACTED, 87 Settings.Global.getInt(mContext.getContentResolver(), 88 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 89 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN)); 90 } 91 92 @Test testReceive_remindMeLater_laterTimes()93 public void testReceive_remindMeLater_laterTimes() { 94 // Test what happens when we receive a "remind me later" intent coming from 95 // a previously-interacted notification that has been rescheduled 96 Settings.Global.putInt(mContext.getContentResolver(), 97 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 98 NotificationManagerService.REVIEW_NOTIF_STATE_RESHOWN); 99 100 // set up Intent action 101 mIntent.setAction(NotificationManagerService.REVIEW_NOTIF_ACTION_REMIND); 102 103 // Upon receipt of the intent, the following things should still happen 104 // regardless of the fact that the user has interacted before: 105 // - notification rescheduled 106 // - notification explicitly canceled 107 // - settings state still indicate user has interacted 108 mReceiver.onReceive(mContext, mIntent); 109 assertTrue(mReceiver.mRescheduled); 110 assertTrue(mReceiver.mCanceled); 111 assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_USER_INTERACTED, 112 Settings.Global.getInt(mContext.getContentResolver(), 113 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 114 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN)); 115 } 116 117 @Test testReceive_dismiss()118 public void testReceive_dismiss() { 119 // Test that dismissing the notification does *not* reschedule the notification, 120 // does cancel it, and writes that it has been dismissed to settings 121 Settings.Global.putInt(mContext.getContentResolver(), 122 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 123 NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW); 124 125 // set up Intent action 126 mIntent.setAction(NotificationManagerService.REVIEW_NOTIF_ACTION_DISMISS); 127 128 // send intent, watch what happens 129 mReceiver.onReceive(mContext, mIntent); 130 assertFalse(mReceiver.mRescheduled); 131 assertTrue(mReceiver.mCanceled); 132 assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_DISMISSED, 133 Settings.Global.getInt(mContext.getContentResolver(), 134 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 135 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN)); 136 } 137 138 @Test testReceive_notificationCanceled_firstSwipe()139 public void testReceive_notificationCanceled_firstSwipe() { 140 // Test the basic swipe away case: the first time the user swipes the notification 141 // away, it will not have been interacted with yet, so make sure it's rescheduled 142 Settings.Global.putInt(mContext.getContentResolver(), 143 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 144 NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW); 145 146 // set up Intent action, would be called from notification's delete intent 147 mIntent.setAction(NotificationManagerService.REVIEW_NOTIF_ACTION_CANCELED); 148 149 // send intent, make sure it gets: 150 // - rescheduled 151 // - not explicitly canceled, the notification was already canceled 152 // - noted that it's been interacted with 153 mReceiver.onReceive(mContext, mIntent); 154 assertTrue(mReceiver.mRescheduled); 155 assertFalse(mReceiver.mCanceled); 156 assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_USER_INTERACTED, 157 Settings.Global.getInt(mContext.getContentResolver(), 158 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 159 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN)); 160 } 161 162 @Test testReceive_notificationCanceled_secondSwipe()163 public void testReceive_notificationCanceled_secondSwipe() { 164 // Test the swipe away case for a rescheduled notification: in this case 165 // it should not be rescheduled anymore 166 Settings.Global.putInt(mContext.getContentResolver(), 167 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 168 NotificationManagerService.REVIEW_NOTIF_STATE_RESHOWN); 169 170 // set up Intent action, would be called from notification's delete intent 171 mIntent.setAction(NotificationManagerService.REVIEW_NOTIF_ACTION_CANCELED); 172 173 // send intent, make sure it gets: 174 // - not rescheduled on the second+ swipe 175 // - not explicitly canceled, the notification was already canceled 176 // - mark as user interacted 177 mReceiver.onReceive(mContext, mIntent); 178 assertFalse(mReceiver.mRescheduled); 179 assertFalse(mReceiver.mCanceled); 180 assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_USER_INTERACTED, 181 Settings.Global.getInt(mContext.getContentResolver(), 182 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 183 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN)); 184 } 185 186 @Test testReceive_notificationCanceled_fromDismiss()187 public void testReceive_notificationCanceled_fromDismiss() { 188 // Test that if the notification delete intent is called due to us canceling 189 // the notification from the receiver, we don't do anything extra 190 Settings.Global.putInt(mContext.getContentResolver(), 191 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 192 NotificationManagerService.REVIEW_NOTIF_STATE_DISMISSED); 193 194 // set up Intent action, would be called from notification's delete intent 195 mIntent.setAction(NotificationManagerService.REVIEW_NOTIF_ACTION_CANCELED); 196 197 // nothing should happen, nothing at all 198 mReceiver.onReceive(mContext, mIntent); 199 assertFalse(mReceiver.mRescheduled); 200 assertFalse(mReceiver.mCanceled); 201 assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_DISMISSED, 202 Settings.Global.getInt(mContext.getContentResolver(), 203 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 204 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN)); 205 } 206 } 207