Loading src/com/android/settings/applications/AppStateNotificationBridge.java +6 −11 Original line number Diff line number Diff line Loading @@ -24,11 +24,7 @@ import android.os.UserManager; import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.Log; import android.util.Slog; import android.view.View; import android.view.ViewGroup; import android.widget.CompoundButton; import android.widget.Switch; import com.android.settings.R; import com.android.settings.Utils; Loading Loading @@ -127,8 +123,7 @@ public class AppStateNotificationBridge extends AppStateBaseBridge { private void addBlockStatus(AppEntry entry, NotificationsSentState stats) { if (stats != null) { stats.blocked = mBackend.getNotificationsBanned(entry.info.packageName, entry.info.uid); stats.systemApp = mBackend.isSystemApp(mContext, entry.info); stats.blockable = !stats.systemApp || (stats.systemApp && stats.blocked); stats.blockable = mBackend.enableSwitch(mContext, entry.info); } } Loading Loading @@ -229,12 +224,14 @@ public class AppStateNotificationBridge extends AppStateBaseBridge { return null; } return (buttonView, isChecked) -> { mBackend.setNotificationsEnabledForPackage( entry.info.packageName, entry.info.uid, isChecked); NotificationsSentState stats = getNotificationsSentState(entry); if (stats != null) { if (stats.blocked == isChecked) { mBackend.setNotificationsEnabledForPackage( entry.info.packageName, entry.info.uid, isChecked); stats.blocked = !isChecked; } } }; } Loading Loading @@ -329,7 +326,6 @@ public class AppStateNotificationBridge extends AppStateBaseBridge { if (stats == null) { return false; } return !stats.blocked; } Loading @@ -344,6 +340,5 @@ public class AppStateNotificationBridge extends AppStateBaseBridge { public int sentCount = 0; public boolean blockable; public boolean blocked; public boolean systemApp; } } src/com/android/settings/notification/NotificationBackend.java +18 −8 Original line number Diff line number Diff line Loading @@ -22,15 +22,20 @@ import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER; import static android.os.UserHandle.USER_SYSTEM; import android.Manifest; import android.app.INotificationManager; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; import android.app.NotificationHistory; import android.app.NotificationManager; import android.app.compat.CompatChanges; import android.app.role.RoleManager; import android.app.usage.IUsageStatsManager; import android.app.usage.UsageEvents; import android.companion.ICompanionDeviceManager; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.compat.annotation.EnabledSince; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading @@ -42,6 +47,7 @@ import android.content.pm.ParceledListSlice; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; Loading Loading @@ -100,12 +106,6 @@ public class NotificationBackend { return row; } public boolean isBlockable(Context context, ApplicationInfo info) { final boolean blocked = getNotificationsBanned(info.packageName, info.uid); final boolean systemApp = isSystemApp(context, info); return !systemApp || (systemApp && blocked); } public AppRow loadAppRow(Context context, PackageManager pm, RoleManager roleManager, PackageInfo app) { final AppRow row = loadAppRow(context, pm, app.applicationInfo); Loading @@ -130,6 +130,15 @@ public class NotificationBackend { || roles.contains(RoleManager.ROLE_EMERGENCY)) { row.systemApp = row.lockedImportance = true; } // if the app targets T but has not requested the permission, we cannot change the // permission state if (app.applicationInfo.targetSdkVersion > Build.VERSION_CODES.S_V2) { if (app.requestedPermissions == null || Arrays.stream(app.requestedPermissions) .noneMatch(p -> p.equals(android.Manifest.permission.POST_NOTIFICATIONS))) { row.lockedImportance = true; } } } else { row.systemApp = Utils.isSystemPackage(context.getResources(), pm, app); List<String> roles = rm.getHeldRolesFromController(app.packageName); Loading Loading @@ -192,14 +201,15 @@ public class NotificationBackend { return sb.toString(); } public boolean isSystemApp(Context context, ApplicationInfo app) { public boolean enableSwitch(Context context, ApplicationInfo app) { try { PackageInfo info = context.getPackageManager().getPackageInfo( app.packageName, PackageManager.GET_SIGNATURES); RoleManager rm = context.getSystemService(RoleManager.class); final AppRow row = new AppRow(); recordCanBeBlocked(context, context.getPackageManager(), rm, info, row); return row.systemApp; boolean systemBlockable = !row.systemApp || (row.systemApp && row.banned); return systemBlockable && !row.lockedImportance; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } Loading tests/robotests/src/com/android/settings/applications/AppStateNotificationBridgeTest.java +4 −6 Original line number Diff line number Diff line Loading @@ -99,7 +99,7 @@ public class AppStateNotificationBridgeTest { when(mState.newSession(any())).thenReturn(mSession); when(mState.getBackgroundLooper()).thenReturn(mock(Looper.class)); when(mBackend.getNotificationsBanned(anyString(), anyInt())).thenReturn(true); when(mBackend.isSystemApp(any(), any())).thenReturn(true); when(mBackend.enableSwitch(any(), any())).thenReturn(true); // most tests assume no work profile when(mUserManager.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{}); mContext = RuntimeEnvironment.application.getApplicationContext(); Loading Loading @@ -245,7 +245,6 @@ public class AppStateNotificationBridgeTest { assertThat(((NotificationsSentState) apps.get(0).extraInfo).avgSentDaily).isEqualTo(1); assertThat(((NotificationsSentState) apps.get(0).extraInfo).avgSentWeekly).isEqualTo(0); assertThat(((NotificationsSentState) apps.get(0).extraInfo).blocked).isTrue(); assertThat(((NotificationsSentState) apps.get(0).extraInfo).systemApp).isTrue(); assertThat(((NotificationsSentState) apps.get(0).extraInfo).blockable).isTrue(); } Loading Loading @@ -376,7 +375,6 @@ public class AppStateNotificationBridgeTest { assertThat(((NotificationsSentState) entry.extraInfo).avgSentDaily).isEqualTo(2); assertThat(((NotificationsSentState) entry.extraInfo).avgSentWeekly).isEqualTo(0); assertThat(((NotificationsSentState) entry.extraInfo).blocked).isTrue(); assertThat(((NotificationsSentState) entry.extraInfo).systemApp).isTrue(); assertThat(((NotificationsSentState) entry.extraInfo).blockable).isTrue(); } Loading Loading @@ -563,11 +561,11 @@ public class AppStateNotificationBridgeTest { entry.extraInfo = new NotificationsSentState(); CompoundButton.OnCheckedChangeListener listener = mBridge.getSwitchOnCheckedListener(entry); listener.onCheckedChanged(toggle, true); listener.onCheckedChanged(toggle, false); verify(mBackend).setNotificationsEnabledForPackage( entry.info.packageName, entry.info.uid, true); assertThat(((NotificationsSentState) entry.extraInfo).blocked).isFalse(); entry.info.packageName, entry.info.uid, false); assertThat(((NotificationsSentState) entry.extraInfo).blocked).isTrue(); } @Test Loading tests/robotests/src/com/android/settings/notification/NotificationBackendTest.java +47 −0 Original line number Diff line number Diff line Loading @@ -37,7 +37,9 @@ import android.content.ComponentName; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; import android.net.MacAddress; import android.os.Build; import android.os.Parcel; import android.provider.Settings; Loading Loading @@ -177,6 +179,51 @@ public class NotificationBackendTest { assertFalse(appRow.lockedImportance); } @Test public void testMarkAppRow_targetsT_noPermissionRequest() throws Exception { Secure.putIntForUser(RuntimeEnvironment.application.getContentResolver(), Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 1, USER_SYSTEM); PackageInfo pi = new PackageInfo(); pi.packageName = "test"; pi.applicationInfo = new ApplicationInfo(); pi.applicationInfo.packageName = "test"; pi.applicationInfo.uid = 123; pi.applicationInfo.targetSdkVersion= Build.VERSION_CODES.TIRAMISU; pi.requestedPermissions = new String[] {"something"}; when(mInm.isPermissionFixed(pi.packageName, 0)).thenReturn(false); AppRow appRow = new NotificationBackend().loadAppRow(RuntimeEnvironment.application, mock(PackageManager.class), mock(RoleManager.class), pi); assertFalse(appRow.systemApp); assertTrue(appRow.lockedImportance); } @Test public void testMarkAppRow_targetsT_permissionRequest() throws Exception { Secure.putIntForUser(RuntimeEnvironment.application.getContentResolver(), Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 1, USER_SYSTEM); PackageInfo pi = new PackageInfo(); pi.packageName = "test"; pi.applicationInfo = new ApplicationInfo(); pi.applicationInfo.packageName = "test"; pi.applicationInfo.uid = 123; pi.applicationInfo.targetSdkVersion= Build.VERSION_CODES.TIRAMISU; pi.requestedPermissions = new String[] {"something", android.Manifest.permission.POST_NOTIFICATIONS}; when(mInm.isPermissionFixed(pi.packageName, 0)).thenReturn(false); AppRow appRow = new NotificationBackend().loadAppRow(RuntimeEnvironment.application, mock(PackageManager.class), mock(RoleManager.class), pi); assertFalse(appRow.systemApp); assertFalse(appRow.lockedImportance); } @Test public void testMarkAppRow_notDefaultPackage() { PackageInfo pi = new PackageInfo(); Loading Loading
src/com/android/settings/applications/AppStateNotificationBridge.java +6 −11 Original line number Diff line number Diff line Loading @@ -24,11 +24,7 @@ import android.os.UserManager; import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.Log; import android.util.Slog; import android.view.View; import android.view.ViewGroup; import android.widget.CompoundButton; import android.widget.Switch; import com.android.settings.R; import com.android.settings.Utils; Loading Loading @@ -127,8 +123,7 @@ public class AppStateNotificationBridge extends AppStateBaseBridge { private void addBlockStatus(AppEntry entry, NotificationsSentState stats) { if (stats != null) { stats.blocked = mBackend.getNotificationsBanned(entry.info.packageName, entry.info.uid); stats.systemApp = mBackend.isSystemApp(mContext, entry.info); stats.blockable = !stats.systemApp || (stats.systemApp && stats.blocked); stats.blockable = mBackend.enableSwitch(mContext, entry.info); } } Loading Loading @@ -229,12 +224,14 @@ public class AppStateNotificationBridge extends AppStateBaseBridge { return null; } return (buttonView, isChecked) -> { mBackend.setNotificationsEnabledForPackage( entry.info.packageName, entry.info.uid, isChecked); NotificationsSentState stats = getNotificationsSentState(entry); if (stats != null) { if (stats.blocked == isChecked) { mBackend.setNotificationsEnabledForPackage( entry.info.packageName, entry.info.uid, isChecked); stats.blocked = !isChecked; } } }; } Loading Loading @@ -329,7 +326,6 @@ public class AppStateNotificationBridge extends AppStateBaseBridge { if (stats == null) { return false; } return !stats.blocked; } Loading @@ -344,6 +340,5 @@ public class AppStateNotificationBridge extends AppStateBaseBridge { public int sentCount = 0; public boolean blockable; public boolean blocked; public boolean systemApp; } }
src/com/android/settings/notification/NotificationBackend.java +18 −8 Original line number Diff line number Diff line Loading @@ -22,15 +22,20 @@ import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER; import static android.os.UserHandle.USER_SYSTEM; import android.Manifest; import android.app.INotificationManager; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; import android.app.NotificationHistory; import android.app.NotificationManager; import android.app.compat.CompatChanges; import android.app.role.RoleManager; import android.app.usage.IUsageStatsManager; import android.app.usage.UsageEvents; import android.companion.ICompanionDeviceManager; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.compat.annotation.EnabledSince; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading @@ -42,6 +47,7 @@ import android.content.pm.ParceledListSlice; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; Loading Loading @@ -100,12 +106,6 @@ public class NotificationBackend { return row; } public boolean isBlockable(Context context, ApplicationInfo info) { final boolean blocked = getNotificationsBanned(info.packageName, info.uid); final boolean systemApp = isSystemApp(context, info); return !systemApp || (systemApp && blocked); } public AppRow loadAppRow(Context context, PackageManager pm, RoleManager roleManager, PackageInfo app) { final AppRow row = loadAppRow(context, pm, app.applicationInfo); Loading @@ -130,6 +130,15 @@ public class NotificationBackend { || roles.contains(RoleManager.ROLE_EMERGENCY)) { row.systemApp = row.lockedImportance = true; } // if the app targets T but has not requested the permission, we cannot change the // permission state if (app.applicationInfo.targetSdkVersion > Build.VERSION_CODES.S_V2) { if (app.requestedPermissions == null || Arrays.stream(app.requestedPermissions) .noneMatch(p -> p.equals(android.Manifest.permission.POST_NOTIFICATIONS))) { row.lockedImportance = true; } } } else { row.systemApp = Utils.isSystemPackage(context.getResources(), pm, app); List<String> roles = rm.getHeldRolesFromController(app.packageName); Loading Loading @@ -192,14 +201,15 @@ public class NotificationBackend { return sb.toString(); } public boolean isSystemApp(Context context, ApplicationInfo app) { public boolean enableSwitch(Context context, ApplicationInfo app) { try { PackageInfo info = context.getPackageManager().getPackageInfo( app.packageName, PackageManager.GET_SIGNATURES); RoleManager rm = context.getSystemService(RoleManager.class); final AppRow row = new AppRow(); recordCanBeBlocked(context, context.getPackageManager(), rm, info, row); return row.systemApp; boolean systemBlockable = !row.systemApp || (row.systemApp && row.banned); return systemBlockable && !row.lockedImportance; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } Loading
tests/robotests/src/com/android/settings/applications/AppStateNotificationBridgeTest.java +4 −6 Original line number Diff line number Diff line Loading @@ -99,7 +99,7 @@ public class AppStateNotificationBridgeTest { when(mState.newSession(any())).thenReturn(mSession); when(mState.getBackgroundLooper()).thenReturn(mock(Looper.class)); when(mBackend.getNotificationsBanned(anyString(), anyInt())).thenReturn(true); when(mBackend.isSystemApp(any(), any())).thenReturn(true); when(mBackend.enableSwitch(any(), any())).thenReturn(true); // most tests assume no work profile when(mUserManager.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{}); mContext = RuntimeEnvironment.application.getApplicationContext(); Loading Loading @@ -245,7 +245,6 @@ public class AppStateNotificationBridgeTest { assertThat(((NotificationsSentState) apps.get(0).extraInfo).avgSentDaily).isEqualTo(1); assertThat(((NotificationsSentState) apps.get(0).extraInfo).avgSentWeekly).isEqualTo(0); assertThat(((NotificationsSentState) apps.get(0).extraInfo).blocked).isTrue(); assertThat(((NotificationsSentState) apps.get(0).extraInfo).systemApp).isTrue(); assertThat(((NotificationsSentState) apps.get(0).extraInfo).blockable).isTrue(); } Loading Loading @@ -376,7 +375,6 @@ public class AppStateNotificationBridgeTest { assertThat(((NotificationsSentState) entry.extraInfo).avgSentDaily).isEqualTo(2); assertThat(((NotificationsSentState) entry.extraInfo).avgSentWeekly).isEqualTo(0); assertThat(((NotificationsSentState) entry.extraInfo).blocked).isTrue(); assertThat(((NotificationsSentState) entry.extraInfo).systemApp).isTrue(); assertThat(((NotificationsSentState) entry.extraInfo).blockable).isTrue(); } Loading Loading @@ -563,11 +561,11 @@ public class AppStateNotificationBridgeTest { entry.extraInfo = new NotificationsSentState(); CompoundButton.OnCheckedChangeListener listener = mBridge.getSwitchOnCheckedListener(entry); listener.onCheckedChanged(toggle, true); listener.onCheckedChanged(toggle, false); verify(mBackend).setNotificationsEnabledForPackage( entry.info.packageName, entry.info.uid, true); assertThat(((NotificationsSentState) entry.extraInfo).blocked).isFalse(); entry.info.packageName, entry.info.uid, false); assertThat(((NotificationsSentState) entry.extraInfo).blocked).isTrue(); } @Test Loading
tests/robotests/src/com/android/settings/notification/NotificationBackendTest.java +47 −0 Original line number Diff line number Diff line Loading @@ -37,7 +37,9 @@ import android.content.ComponentName; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; import android.net.MacAddress; import android.os.Build; import android.os.Parcel; import android.provider.Settings; Loading Loading @@ -177,6 +179,51 @@ public class NotificationBackendTest { assertFalse(appRow.lockedImportance); } @Test public void testMarkAppRow_targetsT_noPermissionRequest() throws Exception { Secure.putIntForUser(RuntimeEnvironment.application.getContentResolver(), Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 1, USER_SYSTEM); PackageInfo pi = new PackageInfo(); pi.packageName = "test"; pi.applicationInfo = new ApplicationInfo(); pi.applicationInfo.packageName = "test"; pi.applicationInfo.uid = 123; pi.applicationInfo.targetSdkVersion= Build.VERSION_CODES.TIRAMISU; pi.requestedPermissions = new String[] {"something"}; when(mInm.isPermissionFixed(pi.packageName, 0)).thenReturn(false); AppRow appRow = new NotificationBackend().loadAppRow(RuntimeEnvironment.application, mock(PackageManager.class), mock(RoleManager.class), pi); assertFalse(appRow.systemApp); assertTrue(appRow.lockedImportance); } @Test public void testMarkAppRow_targetsT_permissionRequest() throws Exception { Secure.putIntForUser(RuntimeEnvironment.application.getContentResolver(), Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 1, USER_SYSTEM); PackageInfo pi = new PackageInfo(); pi.packageName = "test"; pi.applicationInfo = new ApplicationInfo(); pi.applicationInfo.packageName = "test"; pi.applicationInfo.uid = 123; pi.applicationInfo.targetSdkVersion= Build.VERSION_CODES.TIRAMISU; pi.requestedPermissions = new String[] {"something", android.Manifest.permission.POST_NOTIFICATIONS}; when(mInm.isPermissionFixed(pi.packageName, 0)).thenReturn(false); AppRow appRow = new NotificationBackend().loadAppRow(RuntimeEnvironment.application, mock(PackageManager.class), mock(RoleManager.class), pi); assertFalse(appRow.systemApp); assertFalse(appRow.lockedImportance); } @Test public void testMarkAppRow_notDefaultPackage() { PackageInfo pi = new PackageInfo(); Loading