Loading core/res/res/values/config.xml +8 −0 Original line number Diff line number Diff line Loading @@ -4210,6 +4210,14 @@ one bar higher than they actually are --> <bool name="config_inflateSignalStrength">false</bool> <!-- Trigger a warning for notifications with RemoteView objects that are larger in bytes than this value (default 1MB)--> <integer name="config_notificationWarnRemoteViewSizeBytes">1000000</integer> <!-- Strip notification RemoteView objects that are larger in bytes than this value (also log) (default 2MB) --> <integer name="config_notificationStripRemoteViewSizeBytes">2000000</integer> <!-- Sharesheet: define a max number of targets per application for new shortcuts-based direct share introduced in Q --> <integer name="config_maxShortcutTargetsPerApp">3</integer> Loading core/res/res/values/symbols.xml +4 −0 Original line number Diff line number Diff line Loading @@ -3823,5 +3823,9 @@ <java-symbol type="string" name="config_defaultSupervisionProfileOwnerComponent" /> <java-symbol type="bool" name="config_inflateSignalStrength" /> <java-symbol type="integer" name="config_notificationWarnRemoteViewSizeBytes" /> <java-symbol type="integer" name="config_notificationStripRemoteViewSizeBytes" /> <java-symbol type="string" name="config_factoryResetPackage" /> </resources> services/core/java/com/android/server/notification/NotificationManagerService.java +56 −3 Original line number Diff line number Diff line Loading @@ -207,6 +207,7 @@ import android.util.Xml; import android.util.proto.ProtoOutputStream; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.widget.RemoteViews; import android.widget.Toast; import com.android.internal.R; Loading Loading @@ -463,6 +464,9 @@ public class NotificationManagerService extends SystemService { private boolean mIsAutomotive; private boolean mNotificationEffectsEnabledForAutomotive; private int mWarnRemoteViewsSizeBytes; private int mStripRemoteViewsSizeBytes; private MetricsLogger mMetricsLogger; private TriPredicate<String, Integer, String> mAllowedManagedServicePackages; Loading Loading @@ -1723,6 +1727,11 @@ public class NotificationManagerService extends SystemService { mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray( com.android.internal.R.array.config_priorityOnlyDndExemptPackages)); mWarnRemoteViewsSizeBytes = getContext().getResources().getInteger( com.android.internal.R.integer.config_notificationWarnRemoteViewSizeBytes); mStripRemoteViewsSizeBytes = getContext().getResources().getInteger( com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes); } @Override Loading Loading @@ -4712,7 +4721,7 @@ public class NotificationManagerService extends SystemService { // Fix the notification as best we can. try { fixNotification(notification, pkg, userId); fixNotification(notification, pkg, tag, id, userId); } catch (NameNotFoundException e) { Slog.e(TAG, "Cannot create a context for sending app", e); Loading Loading @@ -4817,8 +4826,8 @@ public class NotificationManagerService extends SystemService { } @VisibleForTesting protected void fixNotification(Notification notification, String pkg, int userId) throws NameNotFoundException { protected void fixNotification(Notification notification, String pkg, String tag, int id, int userId) throws NameNotFoundException { final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser( pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId); Loading @@ -4841,6 +4850,50 @@ public class NotificationManagerService extends SystemService { ": Use of fullScreenIntent requires the USE_FULL_SCREEN_INTENT permission"); } } // Remote views? Are they too big? checkRemoteViews(pkg, tag, id, notification); } private void checkRemoteViews(String pkg, String tag, int id, Notification notification) { if (removeRemoteView(pkg, tag, id, notification.contentView)) { notification.contentView = null; } if (removeRemoteView(pkg, tag, id, notification.bigContentView)) { notification.bigContentView = null; } if (removeRemoteView(pkg, tag, id, notification.headsUpContentView)) { notification.headsUpContentView = null; } if (notification.publicVersion != null) { if (removeRemoteView(pkg, tag, id, notification.publicVersion.contentView)) { notification.publicVersion.contentView = null; } if (removeRemoteView(pkg, tag, id, notification.publicVersion.bigContentView)) { notification.publicVersion.bigContentView = null; } if (removeRemoteView(pkg, tag, id, notification.publicVersion.headsUpContentView)) { notification.publicVersion.headsUpContentView = null; } } } private boolean removeRemoteView(String pkg, String tag, int id, RemoteViews contentView) { if (contentView == null) { return false; } final int contentViewSize = contentView.estimateMemoryUsage(); if (contentViewSize > mWarnRemoteViewsSizeBytes && contentViewSize < mStripRemoteViewsSizeBytes) { Slog.w(TAG, "RemoteViews too large on tag: " + tag + " id: " + id + " this might be stripped in a future release"); } if (contentViewSize >= mStripRemoteViewsSizeBytes) { mUsageStats.registerImageRemoved(pkg); Slog.w(TAG, "Removed too large RemoteViews on tag: " + tag + " id: " + id); return true; } return false; } /** Loading services/core/java/com/android/server/notification/NotificationUsageStats.java +17 −1 Original line number Diff line number Diff line Loading @@ -41,7 +41,6 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.PrintWriter; import java.lang.Math; import java.util.ArrayDeque; import java.util.Calendar; import java.util.GregorianCalendar; Loading Loading @@ -263,6 +262,17 @@ public class NotificationUsageStats { } } /** * Call this when RemoteViews object has been removed from a notification because the images * it contains are too big (even after rescaling). */ public synchronized void registerImageRemoved(String packageName) { AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(packageName); for (AggregatedStats stats : aggregatedStatsArray) { stats.numImagesRemoved++; } } // Locked by this. private AggregatedStats[] getAggregatedStatsLocked(NotificationRecord record) { return getAggregatedStatsLocked(record.sbn.getPackageName()); Loading Loading @@ -405,6 +415,7 @@ public class NotificationUsageStats { public int numAlertViolations; public int numQuotaViolations; public long mLastAccessTime; public int numImagesRemoved; public AggregatedStats(Context context, String key) { this.key = key; Loading Loading @@ -529,6 +540,7 @@ public class NotificationUsageStats { maybeCount("note_over_rate", (numRateViolations - previous.numRateViolations)); maybeCount("note_over_alert_rate", (numAlertViolations - previous.numAlertViolations)); maybeCount("note_over_quota", (numQuotaViolations - previous.numQuotaViolations)); maybeCount("note_images_removed", (numImagesRemoved - previous.numImagesRemoved)); noisyImportance.maybeCount(previous.noisyImportance); quietImportance.maybeCount(previous.quietImportance); finalImportance.maybeCount(previous.finalImportance); Loading Loading @@ -562,6 +574,7 @@ public class NotificationUsageStats { previous.numRateViolations = numRateViolations; previous.numAlertViolations = numAlertViolations; previous.numQuotaViolations = numQuotaViolations; previous.numImagesRemoved = numImagesRemoved; noisyImportance.update(previous.noisyImportance); quietImportance.update(previous.quietImportance); finalImportance.update(previous.finalImportance); Loading Loading @@ -667,6 +680,8 @@ public class NotificationUsageStats { output.append("numAlertViolations=").append(numAlertViolations).append("\n"); output.append(indentPlusTwo); output.append("numQuotaViolations=").append(numQuotaViolations).append("\n"); output.append(indentPlusTwo); output.append("numImagesRemoved=").append(numImagesRemoved).append("\n"); output.append(indentPlusTwo).append(noisyImportance.toString()).append("\n"); output.append(indentPlusTwo).append(quietImportance.toString()).append("\n"); output.append(indentPlusTwo).append(finalImportance.toString()).append("\n"); Loading Loading @@ -709,6 +724,7 @@ public class NotificationUsageStats { maybePut(dump, "numQuotaLViolations", numQuotaViolations); maybePut(dump, "notificationEnqueueRate", getEnqueueRate()); maybePut(dump, "numAlertViolations", numAlertViolations); maybePut(dump, "numImagesRemoved", numImagesRemoved); noisyImportance.maybePut(dump, previous.noisyImportance); quietImportance.maybePut(dump, previous.quietImportance); finalImportance.maybePut(dump, previous.finalImportance); Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +94 −6 Original line number Diff line number Diff line Loading @@ -132,6 +132,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; import android.util.Xml; import android.widget.RemoteViews; import androidx.annotation.Nullable; import androidx.test.InstrumentationRegistry; Loading Loading @@ -174,6 +175,7 @@ import java.util.List; import java.util.Map; import java.util.function.Consumer; @SmallTest @RunWith(AndroidTestingRunner.class) @RunWithLooper Loading Loading @@ -348,12 +350,17 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mHandler = mService.new WorkerHandler(mTestableLooper.getLooper()); // MockPackageManager - default returns ApplicationInfo with matching calling UID mContext.setMockPackageManager(mPackageManagerClient); final ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.uid = mUid; when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())) .thenReturn(applicationInfo); .thenAnswer((Answer<ApplicationInfo>) invocation -> { Object[] args = invocation.getArguments(); return getApplicationInfo((String) args[0], mUid); }); when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) .thenReturn(applicationInfo); .thenAnswer((Answer<ApplicationInfo>) invocation -> { Object[] args = invocation.getArguments(); return getApplicationInfo((String) args[0], mUid); }); when(mPackageManagerClient.getPackageUidAsUser(any(), anyInt())).thenReturn(mUid); final LightsManager mockLightsManager = mock(LightsManager.class); when(mockLightsManager.getLight(anyInt())).thenReturn(mock(Light.class)); Loading Loading @@ -389,7 +396,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true); mService.init(mTestableLooper.getLooper(), mPackageManager, mPackageManagerClient, mockLightsManager, mListeners, mAssistants, mConditionProviders, Loading @@ -413,12 +419,32 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @After public void tearDown() throws Exception { mFile.delete(); if (mFile != null) mFile.delete(); clearDeviceConfig(); InstrumentationRegistry.getInstrumentation() .getUiAutomation().dropShellPermissionIdentity(); } private ApplicationInfo getApplicationInfo(String pkg, int uid) { final ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.uid = uid; switch (pkg) { case PKG_N_MR1: applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1; break; case PKG_O: applicationInfo.targetSdkVersion = Build.VERSION_CODES.O; break; case PKG_P: applicationInfo.targetSdkVersion = Build.VERSION_CODES.P; break; default: applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; break; } return applicationInfo; } public void waitForIdle() { mTestableLooper.processAllMessages(); } Loading Loading @@ -5122,4 +5148,66 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals(1, notifsAfter.length); assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0); } @Test public void testRemoveLargeRemoteViews() throws Exception { int removeSize = mContext.getResources().getInteger( com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes); RemoteViews rv = mock(RemoteViews.class); when(rv.estimateMemoryUsage()).thenReturn(removeSize); when(rv.clone()).thenReturn(rv); RemoteViews rv1 = mock(RemoteViews.class); when(rv1.estimateMemoryUsage()).thenReturn(removeSize); when(rv1.clone()).thenReturn(rv1); RemoteViews rv2 = mock(RemoteViews.class); when(rv2.estimateMemoryUsage()).thenReturn(removeSize); when(rv2.clone()).thenReturn(rv2); RemoteViews rv3 = mock(RemoteViews.class); when(rv3.estimateMemoryUsage()).thenReturn(removeSize); when(rv3.clone()).thenReturn(rv3); RemoteViews rv4 = mock(RemoteViews.class); when(rv4.estimateMemoryUsage()).thenReturn(removeSize); when(rv4.clone()).thenReturn(rv4); // note: different! RemoteViews rv5 = mock(RemoteViews.class); when(rv5.estimateMemoryUsage()).thenReturn(removeSize - 1); when(rv5.clone()).thenReturn(rv5); Notification np = new Notification.Builder(mContext, "test") .setSmallIcon(android.R.drawable.sym_def_app_icon) .setContentText("test") .setCustomContentView(rv) .setCustomBigContentView(rv1) .setCustomHeadsUpContentView(rv2) .build(); Notification n = new Notification.Builder(mContext, "test") .setSmallIcon(android.R.drawable.sym_def_app_icon) .setContentText("test") .setCustomContentView(rv3) .setCustomBigContentView(rv4) .setCustomHeadsUpContentView(rv5) .setPublicVersion(np) .build(); assertNotNull(np.contentView); assertNotNull(np.bigContentView); assertNotNull(np.headsUpContentView); assertTrue(n.publicVersion.extras.containsKey(Notification.EXTRA_CONTAINS_CUSTOM_VIEW)); assertNotNull(n.publicVersion.contentView); assertNotNull(n.publicVersion.bigContentView); assertNotNull(n.publicVersion.headsUpContentView); mService.fixNotification(n, PKG, "tag", 9, 0); assertNull(n.contentView); assertNull(n.bigContentView); assertNotNull(n.headsUpContentView); assertNull(n.publicVersion.contentView); assertNull(n.publicVersion.bigContentView); assertNull(n.publicVersion.headsUpContentView); verify(mUsageStats, times(5)).registerImageRemoved(PKG); } } Loading
core/res/res/values/config.xml +8 −0 Original line number Diff line number Diff line Loading @@ -4210,6 +4210,14 @@ one bar higher than they actually are --> <bool name="config_inflateSignalStrength">false</bool> <!-- Trigger a warning for notifications with RemoteView objects that are larger in bytes than this value (default 1MB)--> <integer name="config_notificationWarnRemoteViewSizeBytes">1000000</integer> <!-- Strip notification RemoteView objects that are larger in bytes than this value (also log) (default 2MB) --> <integer name="config_notificationStripRemoteViewSizeBytes">2000000</integer> <!-- Sharesheet: define a max number of targets per application for new shortcuts-based direct share introduced in Q --> <integer name="config_maxShortcutTargetsPerApp">3</integer> Loading
core/res/res/values/symbols.xml +4 −0 Original line number Diff line number Diff line Loading @@ -3823,5 +3823,9 @@ <java-symbol type="string" name="config_defaultSupervisionProfileOwnerComponent" /> <java-symbol type="bool" name="config_inflateSignalStrength" /> <java-symbol type="integer" name="config_notificationWarnRemoteViewSizeBytes" /> <java-symbol type="integer" name="config_notificationStripRemoteViewSizeBytes" /> <java-symbol type="string" name="config_factoryResetPackage" /> </resources>
services/core/java/com/android/server/notification/NotificationManagerService.java +56 −3 Original line number Diff line number Diff line Loading @@ -207,6 +207,7 @@ import android.util.Xml; import android.util.proto.ProtoOutputStream; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.widget.RemoteViews; import android.widget.Toast; import com.android.internal.R; Loading Loading @@ -463,6 +464,9 @@ public class NotificationManagerService extends SystemService { private boolean mIsAutomotive; private boolean mNotificationEffectsEnabledForAutomotive; private int mWarnRemoteViewsSizeBytes; private int mStripRemoteViewsSizeBytes; private MetricsLogger mMetricsLogger; private TriPredicate<String, Integer, String> mAllowedManagedServicePackages; Loading Loading @@ -1723,6 +1727,11 @@ public class NotificationManagerService extends SystemService { mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray( com.android.internal.R.array.config_priorityOnlyDndExemptPackages)); mWarnRemoteViewsSizeBytes = getContext().getResources().getInteger( com.android.internal.R.integer.config_notificationWarnRemoteViewSizeBytes); mStripRemoteViewsSizeBytes = getContext().getResources().getInteger( com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes); } @Override Loading Loading @@ -4712,7 +4721,7 @@ public class NotificationManagerService extends SystemService { // Fix the notification as best we can. try { fixNotification(notification, pkg, userId); fixNotification(notification, pkg, tag, id, userId); } catch (NameNotFoundException e) { Slog.e(TAG, "Cannot create a context for sending app", e); Loading Loading @@ -4817,8 +4826,8 @@ public class NotificationManagerService extends SystemService { } @VisibleForTesting protected void fixNotification(Notification notification, String pkg, int userId) throws NameNotFoundException { protected void fixNotification(Notification notification, String pkg, String tag, int id, int userId) throws NameNotFoundException { final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser( pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId); Loading @@ -4841,6 +4850,50 @@ public class NotificationManagerService extends SystemService { ": Use of fullScreenIntent requires the USE_FULL_SCREEN_INTENT permission"); } } // Remote views? Are they too big? checkRemoteViews(pkg, tag, id, notification); } private void checkRemoteViews(String pkg, String tag, int id, Notification notification) { if (removeRemoteView(pkg, tag, id, notification.contentView)) { notification.contentView = null; } if (removeRemoteView(pkg, tag, id, notification.bigContentView)) { notification.bigContentView = null; } if (removeRemoteView(pkg, tag, id, notification.headsUpContentView)) { notification.headsUpContentView = null; } if (notification.publicVersion != null) { if (removeRemoteView(pkg, tag, id, notification.publicVersion.contentView)) { notification.publicVersion.contentView = null; } if (removeRemoteView(pkg, tag, id, notification.publicVersion.bigContentView)) { notification.publicVersion.bigContentView = null; } if (removeRemoteView(pkg, tag, id, notification.publicVersion.headsUpContentView)) { notification.publicVersion.headsUpContentView = null; } } } private boolean removeRemoteView(String pkg, String tag, int id, RemoteViews contentView) { if (contentView == null) { return false; } final int contentViewSize = contentView.estimateMemoryUsage(); if (contentViewSize > mWarnRemoteViewsSizeBytes && contentViewSize < mStripRemoteViewsSizeBytes) { Slog.w(TAG, "RemoteViews too large on tag: " + tag + " id: " + id + " this might be stripped in a future release"); } if (contentViewSize >= mStripRemoteViewsSizeBytes) { mUsageStats.registerImageRemoved(pkg); Slog.w(TAG, "Removed too large RemoteViews on tag: " + tag + " id: " + id); return true; } return false; } /** Loading
services/core/java/com/android/server/notification/NotificationUsageStats.java +17 −1 Original line number Diff line number Diff line Loading @@ -41,7 +41,6 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.PrintWriter; import java.lang.Math; import java.util.ArrayDeque; import java.util.Calendar; import java.util.GregorianCalendar; Loading Loading @@ -263,6 +262,17 @@ public class NotificationUsageStats { } } /** * Call this when RemoteViews object has been removed from a notification because the images * it contains are too big (even after rescaling). */ public synchronized void registerImageRemoved(String packageName) { AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(packageName); for (AggregatedStats stats : aggregatedStatsArray) { stats.numImagesRemoved++; } } // Locked by this. private AggregatedStats[] getAggregatedStatsLocked(NotificationRecord record) { return getAggregatedStatsLocked(record.sbn.getPackageName()); Loading Loading @@ -405,6 +415,7 @@ public class NotificationUsageStats { public int numAlertViolations; public int numQuotaViolations; public long mLastAccessTime; public int numImagesRemoved; public AggregatedStats(Context context, String key) { this.key = key; Loading Loading @@ -529,6 +540,7 @@ public class NotificationUsageStats { maybeCount("note_over_rate", (numRateViolations - previous.numRateViolations)); maybeCount("note_over_alert_rate", (numAlertViolations - previous.numAlertViolations)); maybeCount("note_over_quota", (numQuotaViolations - previous.numQuotaViolations)); maybeCount("note_images_removed", (numImagesRemoved - previous.numImagesRemoved)); noisyImportance.maybeCount(previous.noisyImportance); quietImportance.maybeCount(previous.quietImportance); finalImportance.maybeCount(previous.finalImportance); Loading Loading @@ -562,6 +574,7 @@ public class NotificationUsageStats { previous.numRateViolations = numRateViolations; previous.numAlertViolations = numAlertViolations; previous.numQuotaViolations = numQuotaViolations; previous.numImagesRemoved = numImagesRemoved; noisyImportance.update(previous.noisyImportance); quietImportance.update(previous.quietImportance); finalImportance.update(previous.finalImportance); Loading Loading @@ -667,6 +680,8 @@ public class NotificationUsageStats { output.append("numAlertViolations=").append(numAlertViolations).append("\n"); output.append(indentPlusTwo); output.append("numQuotaViolations=").append(numQuotaViolations).append("\n"); output.append(indentPlusTwo); output.append("numImagesRemoved=").append(numImagesRemoved).append("\n"); output.append(indentPlusTwo).append(noisyImportance.toString()).append("\n"); output.append(indentPlusTwo).append(quietImportance.toString()).append("\n"); output.append(indentPlusTwo).append(finalImportance.toString()).append("\n"); Loading Loading @@ -709,6 +724,7 @@ public class NotificationUsageStats { maybePut(dump, "numQuotaLViolations", numQuotaViolations); maybePut(dump, "notificationEnqueueRate", getEnqueueRate()); maybePut(dump, "numAlertViolations", numAlertViolations); maybePut(dump, "numImagesRemoved", numImagesRemoved); noisyImportance.maybePut(dump, previous.noisyImportance); quietImportance.maybePut(dump, previous.quietImportance); finalImportance.maybePut(dump, previous.finalImportance); Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +94 −6 Original line number Diff line number Diff line Loading @@ -132,6 +132,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; import android.util.Xml; import android.widget.RemoteViews; import androidx.annotation.Nullable; import androidx.test.InstrumentationRegistry; Loading Loading @@ -174,6 +175,7 @@ import java.util.List; import java.util.Map; import java.util.function.Consumer; @SmallTest @RunWith(AndroidTestingRunner.class) @RunWithLooper Loading Loading @@ -348,12 +350,17 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mHandler = mService.new WorkerHandler(mTestableLooper.getLooper()); // MockPackageManager - default returns ApplicationInfo with matching calling UID mContext.setMockPackageManager(mPackageManagerClient); final ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.uid = mUid; when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())) .thenReturn(applicationInfo); .thenAnswer((Answer<ApplicationInfo>) invocation -> { Object[] args = invocation.getArguments(); return getApplicationInfo((String) args[0], mUid); }); when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) .thenReturn(applicationInfo); .thenAnswer((Answer<ApplicationInfo>) invocation -> { Object[] args = invocation.getArguments(); return getApplicationInfo((String) args[0], mUid); }); when(mPackageManagerClient.getPackageUidAsUser(any(), anyInt())).thenReturn(mUid); final LightsManager mockLightsManager = mock(LightsManager.class); when(mockLightsManager.getLight(anyInt())).thenReturn(mock(Light.class)); Loading Loading @@ -389,7 +396,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true); mService.init(mTestableLooper.getLooper(), mPackageManager, mPackageManagerClient, mockLightsManager, mListeners, mAssistants, mConditionProviders, Loading @@ -413,12 +419,32 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @After public void tearDown() throws Exception { mFile.delete(); if (mFile != null) mFile.delete(); clearDeviceConfig(); InstrumentationRegistry.getInstrumentation() .getUiAutomation().dropShellPermissionIdentity(); } private ApplicationInfo getApplicationInfo(String pkg, int uid) { final ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.uid = uid; switch (pkg) { case PKG_N_MR1: applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1; break; case PKG_O: applicationInfo.targetSdkVersion = Build.VERSION_CODES.O; break; case PKG_P: applicationInfo.targetSdkVersion = Build.VERSION_CODES.P; break; default: applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; break; } return applicationInfo; } public void waitForIdle() { mTestableLooper.processAllMessages(); } Loading Loading @@ -5122,4 +5148,66 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals(1, notifsAfter.length); assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0); } @Test public void testRemoveLargeRemoteViews() throws Exception { int removeSize = mContext.getResources().getInteger( com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes); RemoteViews rv = mock(RemoteViews.class); when(rv.estimateMemoryUsage()).thenReturn(removeSize); when(rv.clone()).thenReturn(rv); RemoteViews rv1 = mock(RemoteViews.class); when(rv1.estimateMemoryUsage()).thenReturn(removeSize); when(rv1.clone()).thenReturn(rv1); RemoteViews rv2 = mock(RemoteViews.class); when(rv2.estimateMemoryUsage()).thenReturn(removeSize); when(rv2.clone()).thenReturn(rv2); RemoteViews rv3 = mock(RemoteViews.class); when(rv3.estimateMemoryUsage()).thenReturn(removeSize); when(rv3.clone()).thenReturn(rv3); RemoteViews rv4 = mock(RemoteViews.class); when(rv4.estimateMemoryUsage()).thenReturn(removeSize); when(rv4.clone()).thenReturn(rv4); // note: different! RemoteViews rv5 = mock(RemoteViews.class); when(rv5.estimateMemoryUsage()).thenReturn(removeSize - 1); when(rv5.clone()).thenReturn(rv5); Notification np = new Notification.Builder(mContext, "test") .setSmallIcon(android.R.drawable.sym_def_app_icon) .setContentText("test") .setCustomContentView(rv) .setCustomBigContentView(rv1) .setCustomHeadsUpContentView(rv2) .build(); Notification n = new Notification.Builder(mContext, "test") .setSmallIcon(android.R.drawable.sym_def_app_icon) .setContentText("test") .setCustomContentView(rv3) .setCustomBigContentView(rv4) .setCustomHeadsUpContentView(rv5) .setPublicVersion(np) .build(); assertNotNull(np.contentView); assertNotNull(np.bigContentView); assertNotNull(np.headsUpContentView); assertTrue(n.publicVersion.extras.containsKey(Notification.EXTRA_CONTAINS_CUSTOM_VIEW)); assertNotNull(n.publicVersion.contentView); assertNotNull(n.publicVersion.bigContentView); assertNotNull(n.publicVersion.headsUpContentView); mService.fixNotification(n, PKG, "tag", 9, 0); assertNull(n.contentView); assertNull(n.bigContentView); assertNotNull(n.headsUpContentView); assertNull(n.publicVersion.contentView); assertNull(n.publicVersion.bigContentView); assertNull(n.publicVersion.headsUpContentView); verify(mUsageStats, times(5)).registerImageRemoved(PKG); } }