diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java index df0d7872bc611..795a8ce3604f7 100644 --- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java +++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java @@ -21,10 +21,13 @@ import android.util.ArraySet; import android.util.SparseArray; import com.android.internal.messages.nano.SystemMessageProto; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import javax.inject.Inject; import javax.inject.Singleton; + /** * Tracks state of foreground services and notifications related to foreground services per user. */ @@ -33,9 +36,11 @@ public class ForegroundServiceController { private final SparseArray mUserServices = new SparseArray<>(); private final Object mMutex = new Object(); + private final NotificationEntryManager mEntryManager; @Inject - public ForegroundServiceController() { + public ForegroundServiceController(NotificationEntryManager entryManager) { + mEntryManager = entryManager; } /** @@ -90,11 +95,18 @@ public class ForegroundServiceController { } /** - * Records active app ops. App Ops are stored in FSC in addition to NotificationData in - * case they change before we have a notification to tag. + * Records active app ops and updates the app op for the pending or visible notifications + * with the given parameters. + * App Ops are stored in FSC in addition to NotificationEntry in case they change before we + * have a notification to tag. + * @param appOpCode code for appOp to add/remove + * @param uid of user the notification is sent to + * @param packageName package that created the notification + * @param active whether the appOpCode is active or not */ - public void onAppOpChanged(int code, int uid, String packageName, boolean active) { + public void onAppOpChanged(int appOpCode, int uid, String packageName, boolean active) { int userId = UserHandle.getUserId(uid); + // Record active app ops synchronized (mMutex) { ForegroundServicesUserState userServices = mUserServices.get(userId); if (userServices == null) { @@ -102,9 +114,30 @@ public class ForegroundServiceController { mUserServices.put(userId, userServices); } if (active) { - userServices.addOp(packageName, code); + userServices.addOp(packageName, appOpCode); } else { - userServices.removeOp(packageName, code); + userServices.removeOp(packageName, appOpCode); + } + } + + // Update appOp if there's an associated pending or visible notification: + final String foregroundKey = getStandardLayoutKey(userId, packageName); + if (foregroundKey != null) { + final NotificationEntry entry = mEntryManager.getPendingOrCurrentNotif(foregroundKey); + if (entry != null + && uid == entry.getSbn().getUid() + && packageName.equals(entry.getSbn().getPackageName())) { + boolean changed; + synchronized (entry.mActiveAppOps) { + if (active) { + changed = entry.mActiveAppOps.add(appOpCode); + } else { + changed = entry.mActiveAppOps.remove(appOpCode); + } + } + if (changed) { + mEntryManager.updateNotifications("appOpChanged pkg=" + packageName); + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java index 4a3b6df6ac903..b983966317f71 100644 --- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java +++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java @@ -21,6 +21,7 @@ import android.app.NotificationManager; import android.content.Context; import android.os.Bundle; import android.service.notification.StatusBarNotification; +import android.util.ArraySet; import android.util.Log; import com.android.internal.statusbar.NotificationVisibility; @@ -40,6 +41,7 @@ public class ForegroundServiceNotificationListener { private final Context mContext; private final ForegroundServiceController mForegroundServiceController; + private final NotificationEntryManager mEntryManager; @Inject public ForegroundServiceNotificationListener(Context context, @@ -47,15 +49,16 @@ public class ForegroundServiceNotificationListener { NotificationEntryManager notificationEntryManager) { mContext = context; mForegroundServiceController = foregroundServiceController; - notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() { + mEntryManager = notificationEntryManager; + mEntryManager.addNotificationEntryListener(new NotificationEntryListener() { @Override public void onPendingEntryAdded(NotificationEntry entry) { - addNotification(entry.getSbn(), entry.getImportance()); + addNotification(entry, entry.getImportance()); } @Override - public void onPostEntryUpdated(NotificationEntry entry) { - updateNotification(entry.getSbn(), entry.getImportance()); + public void onPreEntryUpdated(NotificationEntry entry) { + updateNotification(entry, entry.getImportance()); } @Override @@ -67,15 +70,14 @@ public class ForegroundServiceNotificationListener { } }); - notificationEntryManager.addNotificationLifetimeExtender( - new ForegroundServiceLifetimeExtender()); + mEntryManager.addNotificationLifetimeExtender(new ForegroundServiceLifetimeExtender()); } /** - * @param sbn notification that was just posted + * @param entry notification that was just posted */ - private void addNotification(StatusBarNotification sbn, int importance) { - updateNotification(sbn, importance); + private void addNotification(NotificationEntry entry, int importance) { + updateNotification(entry, importance); } /** @@ -113,9 +115,10 @@ public class ForegroundServiceNotificationListener { } /** - * @param sbn notification that was just changed in some way + * @param entry notification that was just changed in some way */ - private void updateNotification(StatusBarNotification sbn, int newImportance) { + private void updateNotification(NotificationEntry entry, int newImportance) { + final StatusBarNotification sbn = entry.getSbn(); mForegroundServiceController.updateUserState( sbn.getUserId(), userState -> { @@ -143,8 +146,22 @@ public class ForegroundServiceNotificationListener { } } } + tagForeground(entry); return true; }, true /* create if not found */); } + + private void tagForeground(NotificationEntry entry) { + final StatusBarNotification sbn = entry.getSbn(); + ArraySet activeOps = mForegroundServiceController.getAppOps( + sbn.getUserId(), + sbn.getPackageName()); + if (activeOps != null) { + synchronized (entry.mActiveAppOps) { + entry.mActiveAppOps.clear(); + entry.mActiveAppOps.addAll(activeOps); + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java index dfc64508cadfa..df78fa3fd4a4b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java @@ -20,12 +20,12 @@ import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.StatusBarNotification; +import androidx.annotation.NonNull; + import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag; -import androidx.annotation.NonNull; - /** * Listener interface for changes sent by NotificationEntryManager. */ @@ -37,13 +37,6 @@ public interface NotificationEntryListener { default void onPendingEntryAdded(NotificationEntry entry) { } - // TODO: Combine this with onPreEntryUpdated into "onBeforeEntryFiltered" or similar - /** - * Called when a new entry is created but before it has been filtered or displayed to the user. - */ - default void onBeforeNotificationAdded(NotificationEntry entry) { - } - /** * Called when a new entry is created. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index b4dc538f8e0c0..bde097a89f6b8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -262,9 +262,6 @@ public class NotificationEntryManager implements listener.onEntryInflated(entry, inflatedFlags); } mNotificationData.add(entry); - for (NotificationEntryListener listener : mNotificationEntryListeners) { - listener.onBeforeNotificationAdded(entry); - } updateNotifications("onAsyncInflationFinished"); for (NotificationEntryListener listener : mNotificationEntryListeners) { listener.onNotificationAdded(entry); @@ -563,6 +560,18 @@ public class NotificationEntryManager implements return mPendingNotifications.values(); } + /** + * Gets the pending or visible notification entry with the given key. Returns null if + * notification doesn't exist. + */ + public NotificationEntry getPendingOrCurrentNotif(String key) { + if (mPendingNotifications.containsKey(key)) { + return mPendingNotifications.get(key); + } else { + return mNotificationData.get(key); + } + } + private void extendLifetime(NotificationEntry entry, NotificationLifetimeExtender extender) { NotificationLifetimeExtender activeExtender = mRetainedNotifications.get(entry); if (activeExtender != null && activeExtender != extender) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java index 533dfb6ee4aa5..2eefe29cfbba6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java @@ -18,10 +18,6 @@ package com.android.systemui.statusbar.notification; import static com.android.internal.util.Preconditions.checkNotNull; -import android.os.UserHandle; -import android.service.notification.StatusBarNotification; -import android.util.ArraySet; - import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.ForegroundServiceController; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -70,11 +66,6 @@ public class NotificationListController { boolean removedByUser) { mListContainer.cleanUpViewStateForEntry(entry); } - - @Override - public void onBeforeNotificationAdded(NotificationEntry entry) { - tagForeground(entry.getSbn()); - } }; private final DeviceProvisionedListener mDeviceProvisionedListener = @@ -84,29 +75,4 @@ public class NotificationListController { mEntryManager.updateNotifications("device provisioned changed"); } }; - - // TODO: This method is horrifically inefficient - private void tagForeground(StatusBarNotification notification) { - ArraySet activeOps = - mForegroundServiceController.getAppOps( - notification.getUserId(), notification.getPackageName()); - if (activeOps != null) { - int len = activeOps.size(); - for (int i = 0; i < len; i++) { - updateNotificationsForAppOp(activeOps.valueAt(i), notification.getUid(), - notification.getPackageName(), true); - } - } - } - - /** When an app op changes, propagate that change to notifications. */ - public void updateNotificationsForAppOp(int appOp, int uid, String pkg, boolean showIcon) { - String foregroundKey = - mForegroundServiceController.getStandardLayoutKey(UserHandle.getUserId(uid), pkg); - if (foregroundKey != null) { - mEntryManager - .getNotificationData().updateAppOp(appOp, uid, pkg, foregroundKey, showIcon); - mEntryManager.updateNotifications("app opp changed pkg=" + pkg); - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java index 7d0ce5c4fa28d..9981c93431e72 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java @@ -225,24 +225,6 @@ public class NotificationData { updateRankingAndSort(ranking, reason); } - public void updateAppOp(int appOp, int uid, String pkg, String key, boolean showIcon) { - synchronized (mEntries) { - final int len = mEntries.size(); - for (int i = 0; i < len; i++) { - NotificationEntry entry = mEntries.valueAt(i); - if (uid == entry.getSbn().getUid() - && pkg.equals(entry.getSbn().getPackageName()) - && key.equals(entry.getKey())) { - if (showIcon) { - entry.mActiveAppOps.add(appOp); - } else { - entry.mActiveAppOps.remove(appOp); - } - } - } - } - } - /** * Returns true if this notification should be displayed in the high-priority notifications * section diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index 71fc5490d656c..a4c8fc45938f2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -130,7 +130,7 @@ public final class NotificationEntry { private Throwable mDebugThrowable; public CharSequence remoteInputTextWhenReset; public long lastRemoteInputSent = NOT_LAUNCHED_YET; - public ArraySet mActiveAppOps = new ArraySet<>(3); + public final ArraySet mActiveAppOps = new ArraySet<>(3); public CharSequence headsUpStatusBarText; public CharSequence headsUpStatusBarTextPublic; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index b8adfea8b0591..70dca2f8fc100 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -617,7 +617,6 @@ public class StatusBar extends SystemUI implements DemoMode, public void onActiveStateChanged(int code, int uid, String packageName, boolean active) { Dependency.get(MAIN_HANDLER).post(() -> { mForegroundServiceController.onAppOpChanged(code, uid, packageName, active); - mNotificationListController.updateNotificationsForAppOp(code, uid, packageName, active); }); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java index 5c4ef18b61a6a..768bd138fd64c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java @@ -21,11 +21,15 @@ import static junit.framework.Assert.assertNull; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.annotation.UserIdInt; +import android.app.AppOpsManager; import android.app.Notification; import android.app.NotificationManager; import android.os.Bundle; @@ -42,6 +46,8 @@ import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import junit.framework.Assert; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -50,26 +56,103 @@ import org.mockito.ArgumentCaptor; @SmallTest @RunWith(AndroidJUnit4.class) public class ForegroundServiceControllerTest extends SysuiTestCase { - @UserIdInt private static final int USERID_ONE = 10; // UserManagerService.MIN_USER_ID; - @UserIdInt private static final int USERID_TWO = USERID_ONE + 1; - private ForegroundServiceController mFsc; private ForegroundServiceNotificationListener mListener; private NotificationEntryListener mEntryListener; + private NotificationEntryManager mEntryManager; @Before public void setUp() throws Exception { - mFsc = new ForegroundServiceController(); - NotificationEntryManager notificationEntryManager = mock(NotificationEntryManager.class); + mEntryManager = mock(NotificationEntryManager.class); + mFsc = new ForegroundServiceController(mEntryManager); mListener = new ForegroundServiceNotificationListener( - mContext, mFsc, notificationEntryManager); + mContext, mFsc, mEntryManager); ArgumentCaptor entryListenerCaptor = ArgumentCaptor.forClass(NotificationEntryListener.class); - verify(notificationEntryManager).addNotificationEntryListener( + verify(mEntryManager).addNotificationEntryListener( entryListenerCaptor.capture()); mEntryListener = entryListenerCaptor.getValue(); } + @Test + public void testAppOps_appOpChangedBeforeNotificationExists() { + // GIVEN app op exists, but notification doesn't exist in NEM yet + NotificationEntry entry = createFgEntry(); + mFsc.onAppOpChanged( + AppOpsManager.OP_CAMERA, + entry.getSbn().getUid(), + entry.getSbn().getPackageName(), + true); + assertFalse(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA)); + + // WHEN the notification is added + mEntryListener.onPendingEntryAdded(entry); + + // THEN the app op is added to the entry + Assert.assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA)); + } + + @Test + public void testAppOps_appOpAddedToForegroundNotif() { + // GIVEN a notification associated with a foreground service + NotificationEntry entry = addFgEntry(); + when(mEntryManager.getPendingOrCurrentNotif(entry.getKey())).thenReturn(entry); + + // WHEN we are notified of a new app op for this notification + mFsc.onAppOpChanged( + AppOpsManager.OP_CAMERA, + entry.getSbn().getUid(), + entry.getSbn().getPackageName(), + true); + + // THEN the app op is added to the entry + Assert.assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA)); + + // THEN notification views are updated since the notification is visible + verify(mEntryManager, times(1)).updateNotifications(anyString()); + } + + @Test + public void testAppOpsAlreadyAdded() { + // GIVEN a foreground service associated notification that already has the correct app op + NotificationEntry entry = addFgEntry(); + entry.mActiveAppOps.add(AppOpsManager.OP_CAMERA); + when(mEntryManager.getPendingOrCurrentNotif(entry.getKey())).thenReturn(entry); + + // WHEN we are notified of the same app op for this notification + mFsc.onAppOpChanged( + AppOpsManager.OP_CAMERA, + entry.getSbn().getUid(), + entry.getSbn().getPackageName(), + true); + + // THEN the app op still exists in the notification entry + Assert.assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA)); + + // THEN notification views aren't updated since nothing changed + verify(mEntryManager, never()).updateNotifications(anyString()); + } + + @Test + public void testAppOps_appOpNotAddedToUnrelatedNotif() { + // GIVEN no notification entries correspond to the newly updated appOp + NotificationEntry entry = addFgEntry(); + when(mEntryManager.getPendingOrCurrentNotif(entry.getKey())).thenReturn(null); + + // WHEN a new app op is detected + mFsc.onAppOpChanged( + AppOpsManager.OP_CAMERA, + entry.getSbn().getUid(), + entry.getSbn().getPackageName(), + true); + + // THEN we won't see appOps on the entry + Assert.assertFalse(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA)); + + // THEN notification views aren't updated since nothing changed + verify(mEntryManager, never()).updateNotifications(anyString()); + } + @Test public void testAppOpsCRUD() { // no crash on remove that doesn't exist @@ -339,12 +422,12 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); } - private StatusBarNotification makeMockSBN(int userid, String pkg, int id, String tag, + private StatusBarNotification makeMockSBN(int userId, String pkg, int id, String tag, int flags) { final Notification n = mock(Notification.class); n.extras = new Bundle(); n.flags = flags; - return makeMockSBN(userid, pkg, id, tag, n); + return makeMockSBN(userId, pkg, id, tag, n); } private StatusBarNotification makeMockSBN(int userid, String pkg, int id, String tag, @@ -360,10 +443,10 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { return sbn; } - private StatusBarNotification makeMockFgSBN(int userid, String pkg, int id, + private StatusBarNotification makeMockFgSBN(int uid, String pkg, int id, boolean usesStdLayout) { StatusBarNotification sbn = - makeMockSBN(userid, pkg, id, "foo", Notification.FLAG_FOREGROUND_SERVICE); + makeMockSBN(uid, pkg, id, "foo", Notification.FLAG_FOREGROUND_SERVICE); if (usesStdLayout) { sbn.getNotification().contentView = null; sbn.getNotification().headsUpContentView = null; @@ -374,8 +457,8 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { return sbn; } - private StatusBarNotification makeMockFgSBN(int userid, String pkg) { - return makeMockSBN(userid, pkg, 1000, "foo", Notification.FLAG_FOREGROUND_SERVICE); + private StatusBarNotification makeMockFgSBN(int uid, String pkg) { + return makeMockSBN(uid, pkg, 1000, "foo", Notification.FLAG_FOREGROUND_SERVICE); } private StatusBarNotification makeMockDisclosure(int userid, String[] pkgs) { @@ -392,6 +475,19 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { return sbn; } + private NotificationEntry addFgEntry() { + NotificationEntry entry = createFgEntry(); + mEntryListener.onPendingEntryAdded(entry); + return entry; + } + + private NotificationEntry createFgEntry() { + return new NotificationEntryBuilder() + .setSbn(makeMockFgSBN(0, TEST_PACKAGE_NAME, 1000, true)) + .setImportance(NotificationManager.IMPORTANCE_DEFAULT) + .build(); + } + private void entryRemoved(StatusBarNotification notification) { mEntryListener.onEntryRemoved( new NotificationEntryBuilder() @@ -414,6 +510,10 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { .setSbn(notification) .setImportance(importance) .build(); - mEntryListener.onPostEntryUpdated(entry); + mEntryListener.onPreEntryUpdated(entry); } + + @UserIdInt private static final int USERID_ONE = 10; // UserManagerService.MIN_USER_ID; + @UserIdInt private static final int USERID_TWO = USERID_ONE + 1; + private static final String TEST_PACKAGE_NAME = "test"; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index bde7ef97b2ee7..b2a5109749e47 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -140,6 +140,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { @Mock private RowInflaterTask mAsyncInflationTask; @Mock private NotificationRowBinder mMockedRowBinder; + private int mId; private NotificationEntry mEntry; private StatusBarNotification mSbn; private TestableNotificationEntryManager mEntryManager; @@ -243,18 +244,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { when(mListContainer.getViewParentForNotification(any())).thenReturn( new FrameLayout(mContext)); - Notification.Builder n = new Notification.Builder(mContext, "") - .setSmallIcon(R.drawable.ic_person) - .setContentTitle("Title") - .setContentText("Text"); - - mEntry = new NotificationEntryBuilder() - .setPkg(TEST_PACKAGE_NAME) - .setOpPkg(TEST_PACKAGE_NAME) - .setUid(TEST_UID) - .setNotification(n.build()) - .setUser(new UserHandle(ActivityManager.getCurrentUser())) - .build(); + mEntry = createNotification(); mSbn = mEntry.getSbn(); mEntry.expandedIcon = mock(StatusBarIconView.class); @@ -607,6 +597,22 @@ public class NotificationEntryManagerTest extends SysuiTestCase { any(NotificationVisibility.class), anyBoolean()); } + private NotificationEntry createNotification() { + Notification.Builder n = new Notification.Builder(mContext, "") + .setSmallIcon(R.drawable.ic_person) + .setContentTitle("Title") + .setContentText("Text"); + + return new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_NAME) + .setOpPkg(TEST_PACKAGE_NAME) + .setUid(TEST_UID) + .setId(mId++) + .setNotification(n.build()) + .setUser(new UserHandle(ActivityManager.getCurrentUser())) + .build(); + } + private Notification.Action createAction() { return new Notification.Action.Builder( Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java index 2435bb92b08d4..c2d2e3158f544 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java @@ -16,24 +16,16 @@ package com.android.systemui.statusbar.notification; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertTrue; - -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; -import android.app.AppOpsManager; import android.app.Notification; import android.os.UserHandle; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; -import android.util.ArraySet; import androidx.test.filters.SmallTest; @@ -123,107 +115,6 @@ public class NotificationListControllerTest extends SysuiTestCase { verify(mEntryManager).updateNotifications(anyString()); } - @Test - public void testAppOps_appOpAddedToForegroundNotif() { - // GIVEN a notification associated with a foreground service - final NotificationEntry entry = buildEntry(); - mNotificationData.add(entry); - when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString())) - .thenReturn(entry.getKey()); - - // WHEN we are notified of a new app op - mController.updateNotificationsForAppOp( - AppOpsManager.OP_CAMERA, - entry.getSbn().getUid(), - entry.getSbn().getPackageName(), - true); - - // THEN the app op is added to the entry - assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA)); - // THEN updateNotifications(TEST) is called - verify(mEntryManager, times(1)).updateNotifications(anyString()); - } - - @Test - public void testAppOps_appOpAddedToUnrelatedNotif() { - // GIVEN No current foreground notifs - when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString())) - .thenReturn(null); - - // WHEN An unrelated notification gets a new app op - mController.updateNotificationsForAppOp(AppOpsManager.OP_CAMERA, 1000, "pkg", true); - - // THEN We never call updateNotifications(TEST) - verify(mEntryManager, never()).updateNotifications(anyString()); - } - - @Test - public void testAppOps_addNotificationWithExistingAppOps() { - // GIVEN a notification with three associated app ops that is associated with a foreground - // service - final NotificationEntry entry = buildEntry(); - mNotificationData.add(entry); - ArraySet expected = new ArraySet<>(); - expected.add(3); - expected.add(235); - expected.add(1); - when(mForegroundServiceController.getStandardLayoutKey( - entry.getSbn().getUserId(), - entry.getSbn().getPackageName())).thenReturn(entry.getKey()); - when(mForegroundServiceController.getAppOps(entry.getSbn().getUserId(), - entry.getSbn().getPackageName())).thenReturn(expected); - - // WHEN the notification is added - mEntryListener.onBeforeNotificationAdded(entry); - - // THEN the entry is tagged with all three app ops - assertEquals(expected.size(), entry.mActiveAppOps.size()); - for (int op : expected) { - assertTrue("Entry missing op " + op, entry.mActiveAppOps.contains(op)); - } - } - - @Test - public void testAdd_addNotificationWithNoExistingAppOps() { - // GIVEN a notification with NO associated app ops - final NotificationEntry entry = buildEntry(); - - mNotificationData.add(entry); - when(mForegroundServiceController.getStandardLayoutKey( - entry.getSbn().getUserId(), - entry.getSbn().getPackageName())).thenReturn(entry.getKey()); - when(mForegroundServiceController.getAppOps(entry.getSbn().getUserId(), - entry.getSbn().getPackageName())).thenReturn(null); - - // WHEN the notification is added - mEntryListener.onBeforeNotificationAdded(entry); - - // THEN the entry doesn't have any app ops associated with it - assertEquals(0, entry.mActiveAppOps.size()); - } - - @Test - public void testAdd_addNonForegroundNotificationWithExistingAppOps() { - // GIVEN a notification with app ops that isn't associated with a foreground service - final NotificationEntry entry = buildEntry(); - mNotificationData.add(entry); - ArraySet ops = new ArraySet<>(); - ops.add(3); - ops.add(235); - ops.add(1); - when(mForegroundServiceController.getAppOps(entry.getSbn().getUserId(), - entry.getSbn().getPackageName())).thenReturn(ops); - when(mForegroundServiceController.getStandardLayoutKey( - entry.getSbn().getUserId(), - entry.getSbn().getPackageName())).thenReturn("something else"); - - // WHEN the notification is added - mEntryListener.onBeforeNotificationAdded(entry); - - // THEN the entry doesn't have any app ops associated with it - assertEquals(0, entry.mActiveAppOps.size()); - } - private NotificationEntry buildEntry() { mNextNotifId++; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java index dba0174f2626c..1a469d881d2cd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java @@ -16,8 +16,6 @@ package com.android.systemui.statusbar.notification.collection; -import static android.app.AppOpsManager.OP_ACCEPT_HANDOVER; -import static android.app.AppOpsManager.OP_CAMERA; import static android.app.Notification.CATEGORY_ALARM; import static android.app.Notification.CATEGORY_CALL; import static android.app.Notification.CATEGORY_EVENT; @@ -56,7 +54,6 @@ import android.content.pm.PackageManager; import android.graphics.drawable.Icon; import android.media.session.MediaSession; import android.os.Bundle; -import android.os.Process; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.SnoozeCriterion; @@ -64,7 +61,6 @@ import android.service.notification.StatusBarNotification; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; -import android.util.ArraySet; import androidx.test.filters.SmallTest; @@ -159,69 +155,6 @@ public class NotificationDataTest extends SysuiTestCase { assertEquals(NOTIFICATION_CHANNEL, mRow.getEntry().getChannel()); } - @Test - public void testAllRelevantNotisTaggedWithAppOps() throws Exception { - mNotificationData.add(mRow.getEntry()); - ExpandableNotificationRow row2 = new NotificationTestHelper(getContext(), mDependency) - .createRow(); - mNotificationData.add(row2.getEntry()); - ExpandableNotificationRow diffPkg = - new NotificationTestHelper(getContext(), mDependency).createRow("pkg", 4000, - Process.myUserHandle()); - mNotificationData.add(diffPkg.getEntry()); - - ArraySet expectedOps = new ArraySet<>(); - expectedOps.add(OP_CAMERA); - expectedOps.add(OP_ACCEPT_HANDOVER); - - for (int op : expectedOps) { - mNotificationData.updateAppOp(op, NotificationTestHelper.UID, - NotificationTestHelper.PKG, mRow.getEntry().getKey(), true); - mNotificationData.updateAppOp(op, NotificationTestHelper.UID, - NotificationTestHelper.PKG, row2.getEntry().getKey(), true); - } - for (int op : expectedOps) { - assertTrue(mRow.getEntry().getKey() + " doesn't have op " + op, - mNotificationData.get(mRow.getEntry().getKey()).mActiveAppOps.contains(op)); - assertTrue(row2.getEntry().getKey() + " doesn't have op " + op, - mNotificationData.get(row2.getEntry().getKey()).mActiveAppOps.contains(op)); - assertFalse(diffPkg.getEntry().getKey() + " has op " + op, - mNotificationData.get(diffPkg.getEntry().getKey()).mActiveAppOps.contains(op)); - } - } - - @Test - public void testAppOpsRemoval() throws Exception { - mNotificationData.add(mRow.getEntry()); - ExpandableNotificationRow row2 = new NotificationTestHelper(getContext(), mDependency) - .createRow(); - mNotificationData.add(row2.getEntry()); - - ArraySet expectedOps = new ArraySet<>(); - expectedOps.add(OP_CAMERA); - expectedOps.add(OP_ACCEPT_HANDOVER); - - for (int op : expectedOps) { - mNotificationData.updateAppOp(op, NotificationTestHelper.UID, - NotificationTestHelper.PKG, row2.getEntry().getKey(), true); - } - - expectedOps.remove(OP_ACCEPT_HANDOVER); - mNotificationData.updateAppOp(OP_ACCEPT_HANDOVER, NotificationTestHelper.UID, - NotificationTestHelper.PKG, row2.getEntry().getKey(), false); - - assertTrue(mRow.getEntry().getKey() + " doesn't have op " + OP_CAMERA, - mNotificationData.get(mRow.getEntry().getKey()).mActiveAppOps.contains(OP_CAMERA)); - assertTrue(row2.getEntry().getKey() + " doesn't have op " + OP_CAMERA, - mNotificationData.get(row2.getEntry().getKey()).mActiveAppOps.contains(OP_CAMERA)); - assertFalse(mRow.getEntry().getKey() + " has op " + OP_ACCEPT_HANDOVER, - mNotificationData.get(mRow.getEntry().getKey()) - .mActiveAppOps.contains(OP_ACCEPT_HANDOVER)); - assertFalse(row2.getEntry().getKey() + " has op " + OP_ACCEPT_HANDOVER, - mNotificationData.get(row2.getEntry().getKey()) - .mActiveAppOps.contains(OP_ACCEPT_HANDOVER)); - } - @Test public void testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications() throws Exception {