1 // Copyright 2019 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.chrome.browser.browserservices.permissiondelegation; 6 7 import static org.mockito.ArgumentMatchers.any; 8 import static org.mockito.ArgumentMatchers.anyBoolean; 9 import static org.mockito.ArgumentMatchers.anyInt; 10 import static org.mockito.ArgumentMatchers.anyString; 11 import static org.mockito.ArgumentMatchers.eq; 12 import static org.mockito.Mockito.doAnswer; 13 import static org.mockito.Mockito.never; 14 import static org.mockito.Mockito.verify; 15 import static org.robolectric.Shadows.shadowOf; 16 17 import android.content.ComponentName; 18 import android.content.Intent; 19 import android.content.pm.PackageManager; 20 import android.content.pm.ResolveInfo; 21 22 import org.junit.Before; 23 import org.junit.Rule; 24 import org.junit.Test; 25 import org.junit.rules.TestRule; 26 import org.junit.runner.RunWith; 27 import org.mockito.Mock; 28 import org.mockito.MockitoAnnotations; 29 import org.robolectric.RuntimeEnvironment; 30 import org.robolectric.annotation.Config; 31 import org.robolectric.shadows.ShadowPackageManager; 32 33 import org.chromium.base.test.BaseRobolectricTestRunner; 34 import org.chromium.base.test.util.Feature; 35 import org.chromium.chrome.browser.browserservices.TrustedWebActivityClient; 36 import org.chromium.chrome.test.util.browser.Features; 37 import org.chromium.components.content_settings.ContentSettingsType; 38 import org.chromium.components.embedder_support.util.Origin; 39 40 /** 41 * Tests for {@link NotificationPermissionUpdater}. 42 */ 43 @RunWith(BaseRobolectricTestRunner.class) 44 @Config(manifest = Config.NONE) 45 public class NotificationPermissionUpdaterTest { 46 private static final Origin ORIGIN = Origin.create("https://www.website.com"); 47 private static final String PACKAGE_NAME = "com.package.name"; 48 private static final String OTHER_PACKAGE_NAME = "com.other.package.name"; 49 50 @Rule 51 public TestRule mProcessor = new Features.JUnitProcessor(); 52 53 @Mock public TrustedWebActivityPermissionManager mPermissionManager; 54 @Mock public TrustedWebActivityClient mTrustedWebActivityClient; 55 56 private NotificationPermissionUpdater mNotificationPermissionUpdater; 57 private ShadowPackageManager mShadowPackageManager; 58 59 private boolean mNotificationsEnabled; 60 61 @Before setUp()62 public void setUp() { 63 MockitoAnnotations.initMocks(this); 64 65 PackageManager pm = RuntimeEnvironment.application.getPackageManager(); 66 mShadowPackageManager = shadowOf(pm); 67 mNotificationPermissionUpdater = 68 new NotificationPermissionUpdater(mPermissionManager, mTrustedWebActivityClient); 69 70 installBrowsableIntentHandler(ORIGIN, PACKAGE_NAME); 71 } 72 73 @Test 74 @Feature("TrustedWebActivities") doesntRegister_whenClientDoesntHaveService()75 public void doesntRegister_whenClientDoesntHaveService() { 76 mNotificationPermissionUpdater.onOriginVerified(ORIGIN, PACKAGE_NAME); 77 78 verifyPermissionNotUpdated(); 79 } 80 81 @Test 82 @Feature("TrustedWebActivities") disablesNotifications_whenClientNotificationsAreDisabled()83 public void disablesNotifications_whenClientNotificationsAreDisabled() { 84 installTrustedWebActivityService(ORIGIN, PACKAGE_NAME); 85 setNotificationsEnabledForClient(false); 86 87 mNotificationPermissionUpdater.onOriginVerified(ORIGIN, PACKAGE_NAME); 88 89 verifyPermissionUpdated(false); 90 } 91 92 @Test 93 @Feature("TrustedWebActivities") enablesNotifications_whenClientNotificationsAreEnabled()94 public void enablesNotifications_whenClientNotificationsAreEnabled() { 95 installTrustedWebActivityService(ORIGIN, PACKAGE_NAME); 96 setNotificationsEnabledForClient(true); 97 98 mNotificationPermissionUpdater.onOriginVerified(ORIGIN, PACKAGE_NAME); 99 100 verifyPermissionUpdated(true); 101 } 102 103 @Test 104 @Feature("TrustedWebActivities") updatesPermission_onSubsequentCalls()105 public void updatesPermission_onSubsequentCalls() { 106 107 installTrustedWebActivityService(ORIGIN, PACKAGE_NAME); 108 setNotificationsEnabledForClient(true); 109 mNotificationPermissionUpdater.onOriginVerified(ORIGIN, PACKAGE_NAME); 110 verifyPermissionUpdated(true); 111 112 setNotificationsEnabledForClient(false); 113 mNotificationPermissionUpdater.onOriginVerified(ORIGIN, PACKAGE_NAME); 114 verifyPermissionUpdated(false); 115 } 116 117 @Test 118 @Feature("TrustedWebActivities") updatesPermission_onNewClient()119 public void updatesPermission_onNewClient() { 120 installTrustedWebActivityService(ORIGIN, PACKAGE_NAME); 121 setNotificationsEnabledForClient(true); 122 mNotificationPermissionUpdater.onOriginVerified(ORIGIN, PACKAGE_NAME); 123 verifyPermissionUpdated(true); 124 125 installTrustedWebActivityService(ORIGIN, OTHER_PACKAGE_NAME); 126 setNotificationsEnabledForClient(false); 127 mNotificationPermissionUpdater.onOriginVerified(ORIGIN, OTHER_PACKAGE_NAME); 128 verifyPermissionUpdated(OTHER_PACKAGE_NAME, false); 129 } 130 131 @Test 132 @Feature("TrustedWebActivities") unregisters_onClientUninstall()133 public void unregisters_onClientUninstall() { 134 installTrustedWebActivityService(ORIGIN, PACKAGE_NAME); 135 setNotificationsEnabledForClient(true); 136 137 mNotificationPermissionUpdater.onOriginVerified(ORIGIN, PACKAGE_NAME); 138 139 uninstallTrustedWebActivityService(ORIGIN); 140 mNotificationPermissionUpdater.onClientAppUninstalled(ORIGIN); 141 142 verifyPermissionUnregistered(); 143 } 144 145 @Test 146 @Feature("TrustedWebActivities") doesntUnregister_whenOtherClientsRemain()147 public void doesntUnregister_whenOtherClientsRemain() { 148 149 installTrustedWebActivityService(ORIGIN, PACKAGE_NAME); 150 setNotificationsEnabledForClient(true); 151 152 mNotificationPermissionUpdater.onOriginVerified(ORIGIN, PACKAGE_NAME); 153 verifyPermissionUpdated(true); 154 155 // Since we haven't called uninstallTrustedWebActivityService, the Updater sees that 156 // notifications can still be handled by other apps. We don't unregister, but we do update 157 // to the permission to that of the other app. 158 setNotificationsEnabledForClient(false); 159 mNotificationPermissionUpdater.onClientAppUninstalled(ORIGIN); 160 verifyPermissionNotUnregistered(); 161 verifyPermissionUpdated(false); 162 163 uninstallTrustedWebActivityService(ORIGIN); 164 mNotificationPermissionUpdater.onClientAppUninstalled(ORIGIN); 165 verifyPermissionUnregistered(); 166 } 167 168 /** "Installs" the given package to handle intents for that origin. */ installBrowsableIntentHandler(Origin origin, String packageName)169 private void installBrowsableIntentHandler(Origin origin, String packageName) { 170 Intent intent = new Intent(); 171 intent.setPackage(packageName); 172 intent.setData(origin.uri()); 173 intent.setAction(Intent.ACTION_VIEW); 174 intent.addCategory(Intent.CATEGORY_BROWSABLE); 175 176 mShadowPackageManager.addResolveInfoForIntent(intent, new ResolveInfo()); 177 } 178 179 /** "Installs" a Trusted Web Activity Service for the origin. */ 180 @SuppressWarnings("unchecked") installTrustedWebActivityService(Origin origin, String packageName)181 private void installTrustedWebActivityService(Origin origin, String packageName) { 182 doAnswer(invocation -> { 183 TrustedWebActivityClient.PermissionCheckCallback callback = 184 invocation.getArgument(1); 185 callback.onPermissionCheck( 186 new ComponentName(packageName, "FakeClass"), 187 mNotificationsEnabled); 188 return true; 189 }).when(mTrustedWebActivityClient).checkNotificationPermission(eq(origin), any()); 190 } 191 setNotificationsEnabledForClient(boolean enabled)192 private void setNotificationsEnabledForClient(boolean enabled) { 193 mNotificationsEnabled = enabled; 194 } 195 uninstallTrustedWebActivityService(Origin origin)196 private void uninstallTrustedWebActivityService(Origin origin) { 197 doAnswer(invocation -> { 198 TrustedWebActivityClient.PermissionCheckCallback callback = 199 invocation.getArgument(1); 200 callback.onNoTwaFound(); 201 return true; 202 }).when(mTrustedWebActivityClient).checkNotificationPermission(eq(origin), any()); 203 } 204 verifyPermissionNotUpdated()205 private void verifyPermissionNotUpdated() { 206 verify(mPermissionManager, never()) 207 .updatePermission(any(), anyString(), anyInt(), anyBoolean()); 208 } 209 verifyPermissionUpdated(boolean enabled)210 private void verifyPermissionUpdated(boolean enabled) { 211 verifyPermissionUpdated(PACKAGE_NAME, enabled); 212 } 213 verifyPermissionUpdated(String packageName, boolean enabled)214 private void verifyPermissionUpdated(String packageName, boolean enabled) { 215 verify(mPermissionManager) 216 .updatePermission(eq(ORIGIN), eq(packageName), 217 eq(ContentSettingsType.NOTIFICATIONS), eq(enabled)); 218 } 219 verifyPermissionUnregistered()220 private void verifyPermissionUnregistered() { 221 verify(mPermissionManager).unregister(eq(ORIGIN)); 222 } 223 verifyPermissionNotUnregistered()224 private void verifyPermissionNotUnregistered() { 225 verify(mPermissionManager, never()).unregister(eq(ORIGIN)); 226 } 227 } 228