Loading services/core/java/com/android/server/notification/NotificationManagerService.java +31 −1 Original line number Diff line number Diff line Loading @@ -220,6 +220,7 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.LauncherApps; import android.content.pm.ModuleInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; Loading Loading @@ -675,6 +676,10 @@ public class NotificationManagerService extends SystemService { private static final int DB_VERSION = 1; private static final String ADSERVICES_MODULE_PKG_NAME = "com.android.adservices"; private static final String TAG_NOTIFICATION_POLICY = "notification-policy"; private static final String ATTR_VERSION = "version"; Loading Loading @@ -736,6 +741,8 @@ public class NotificationManagerService extends SystemService { private AppOpsManager.OnOpChangedListener mAppOpsListener; private ModuleInfo mAdservicesModuleInfo; static class Archive { final SparseArray<Boolean> mEnabled; final int mBufferSize; Loading Loading @@ -2934,6 +2941,15 @@ public class NotificationManagerService extends SystemService { mZenModeHelper.setDeviceEffectsApplier( new DefaultDeviceEffectsApplier(getContext())); } List<ModuleInfo> moduleInfoList = mPackageManagerClient.getInstalledModules( PackageManager.MATCH_DEBUG_TRIAGED_MISSING); // Cache adservices module info for (ModuleInfo mi : moduleInfoList) { if (Objects.equals(mi.getApexModuleName(), ADSERVICES_MODULE_PKG_NAME)) { mAdservicesModuleInfo = mi; } } } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { mSnoozeHelper.scheduleRepostsForPersistedNotifications(System.currentTimeMillis()); } else if (phase == SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY) { Loading Loading @@ -7683,13 +7699,27 @@ public class NotificationManagerService extends SystemService { private boolean canBeNonDismissible(ApplicationInfo ai, Notification notification) { return notification.isMediaNotification() || isEnterpriseExempted(ai) || notification.isStyle(Notification.CallStyle.class) || isDefaultSearchSelectorPackage(ai.packageName); || isDefaultSearchSelectorPackage(ai.packageName) || isDefaultAdservicesPackage(ai.packageName); } private boolean isDefaultSearchSelectorPackage(String pkg) { return Objects.equals(mDefaultSearchSelectorPkg, pkg); } private boolean isDefaultAdservicesPackage(String pkg) { if (mAdservicesModuleInfo == null) { return false; } // Handles the special package structure for mainline modules for (String apkName : mAdservicesModuleInfo.getApkInApexPackageNames()) { if (Objects.equals(apkName, pkg)) { return true; } } return false; } private boolean isEnterpriseExempted(ApplicationInfo ai) { // Check if the app is an organization admin app // TODO(b/234609037): Replace with new DPM APIs to check if organization admin Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +36 −1 Original line number Diff line number Diff line Loading @@ -200,6 +200,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.LauncherApps; import android.content.pm.ModuleInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; Loading Loading @@ -450,6 +451,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { private static final String VALID_CONVO_SHORTCUT_ID = "shortcut"; private static final String SEARCH_SELECTOR_PKG = "searchSelector"; private static final String ADSERVICES_MODULE_PKG = "com.android.adservices"; private static final String ADSERVICES_APK_PKG = "com.android.adservices.api"; @Mock private NotificationListeners mListeners; @Mock Loading Loading @@ -740,7 +744,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Return first true for RoleObserver main-thread check when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false); ModuleInfo moduleInfo = new ModuleInfo(); moduleInfo.setApexModuleName(ADSERVICES_MODULE_PKG); moduleInfo.setApkInApexPackageNames(List.of(ADSERVICES_APK_PKG)); when(mPackageManagerClient.getInstalledModules(anyInt())) .thenReturn(List.of(moduleInfo)); if (upToBootPhase >= SystemService.PHASE_SYSTEM_SERVICES_READY) { mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper); } Loading Loading @@ -13217,6 +13225,33 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); } @Test public void fixSystemNotification_defaultAdservices_withOnGoingFlag_nondismissible() throws Exception { final ApplicationInfo ai = new ApplicationInfo(); ai.packageName = ADSERVICES_APK_PKG; ai.uid = mUid; ai.flags |= ApplicationInfo.FLAG_SYSTEM; when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) .thenReturn(ai); when(mAppOpsManager.checkOpNoThrow( AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid, ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED); // Given: a notification from an app on the system partition has the flag // FLAG_ONGOING_EVENT set Notification n = new Notification.Builder(mContext, "test") .setOngoing(true) .build(); // When: fix the notification with NotificationManagerService mService.fixNotification(n, ADSERVICES_APK_PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); // Then: the notification's flag FLAG_NO_DISMISS should be set assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); } @Test public void fixCallNotification_withOnGoingFlag_shouldNotBeNonDismissible() throws Exception { Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +31 −1 Original line number Diff line number Diff line Loading @@ -220,6 +220,7 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.LauncherApps; import android.content.pm.ModuleInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; Loading Loading @@ -675,6 +676,10 @@ public class NotificationManagerService extends SystemService { private static final int DB_VERSION = 1; private static final String ADSERVICES_MODULE_PKG_NAME = "com.android.adservices"; private static final String TAG_NOTIFICATION_POLICY = "notification-policy"; private static final String ATTR_VERSION = "version"; Loading Loading @@ -736,6 +741,8 @@ public class NotificationManagerService extends SystemService { private AppOpsManager.OnOpChangedListener mAppOpsListener; private ModuleInfo mAdservicesModuleInfo; static class Archive { final SparseArray<Boolean> mEnabled; final int mBufferSize; Loading Loading @@ -2934,6 +2941,15 @@ public class NotificationManagerService extends SystemService { mZenModeHelper.setDeviceEffectsApplier( new DefaultDeviceEffectsApplier(getContext())); } List<ModuleInfo> moduleInfoList = mPackageManagerClient.getInstalledModules( PackageManager.MATCH_DEBUG_TRIAGED_MISSING); // Cache adservices module info for (ModuleInfo mi : moduleInfoList) { if (Objects.equals(mi.getApexModuleName(), ADSERVICES_MODULE_PKG_NAME)) { mAdservicesModuleInfo = mi; } } } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { mSnoozeHelper.scheduleRepostsForPersistedNotifications(System.currentTimeMillis()); } else if (phase == SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY) { Loading Loading @@ -7683,13 +7699,27 @@ public class NotificationManagerService extends SystemService { private boolean canBeNonDismissible(ApplicationInfo ai, Notification notification) { return notification.isMediaNotification() || isEnterpriseExempted(ai) || notification.isStyle(Notification.CallStyle.class) || isDefaultSearchSelectorPackage(ai.packageName); || isDefaultSearchSelectorPackage(ai.packageName) || isDefaultAdservicesPackage(ai.packageName); } private boolean isDefaultSearchSelectorPackage(String pkg) { return Objects.equals(mDefaultSearchSelectorPkg, pkg); } private boolean isDefaultAdservicesPackage(String pkg) { if (mAdservicesModuleInfo == null) { return false; } // Handles the special package structure for mainline modules for (String apkName : mAdservicesModuleInfo.getApkInApexPackageNames()) { if (Objects.equals(apkName, pkg)) { return true; } } return false; } private boolean isEnterpriseExempted(ApplicationInfo ai) { // Check if the app is an organization admin app // TODO(b/234609037): Replace with new DPM APIs to check if organization admin Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +36 −1 Original line number Diff line number Diff line Loading @@ -200,6 +200,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.LauncherApps; import android.content.pm.ModuleInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; Loading Loading @@ -450,6 +451,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { private static final String VALID_CONVO_SHORTCUT_ID = "shortcut"; private static final String SEARCH_SELECTOR_PKG = "searchSelector"; private static final String ADSERVICES_MODULE_PKG = "com.android.adservices"; private static final String ADSERVICES_APK_PKG = "com.android.adservices.api"; @Mock private NotificationListeners mListeners; @Mock Loading Loading @@ -740,7 +744,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Return first true for RoleObserver main-thread check when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false); ModuleInfo moduleInfo = new ModuleInfo(); moduleInfo.setApexModuleName(ADSERVICES_MODULE_PKG); moduleInfo.setApkInApexPackageNames(List.of(ADSERVICES_APK_PKG)); when(mPackageManagerClient.getInstalledModules(anyInt())) .thenReturn(List.of(moduleInfo)); if (upToBootPhase >= SystemService.PHASE_SYSTEM_SERVICES_READY) { mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper); } Loading Loading @@ -13217,6 +13225,33 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); } @Test public void fixSystemNotification_defaultAdservices_withOnGoingFlag_nondismissible() throws Exception { final ApplicationInfo ai = new ApplicationInfo(); ai.packageName = ADSERVICES_APK_PKG; ai.uid = mUid; ai.flags |= ApplicationInfo.FLAG_SYSTEM; when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) .thenReturn(ai); when(mAppOpsManager.checkOpNoThrow( AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid, ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED); // Given: a notification from an app on the system partition has the flag // FLAG_ONGOING_EVENT set Notification n = new Notification.Builder(mContext, "test") .setOngoing(true) .build(); // When: fix the notification with NotificationManagerService mService.fixNotification(n, ADSERVICES_APK_PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); // Then: the notification's flag FLAG_NO_DISMISS should be set assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); } @Test public void fixCallNotification_withOnGoingFlag_shouldNotBeNonDismissible() throws Exception {