Remove onBeforeNotificationAdded call
By moving where appOps of notifications gets set When appOps change: StatusBar detects appOp change and propogates change to ForegroundServiceController which stores appOp change (in case notification hasn't been added yet). This controller will also update the appOps of the relevant pending/visible notification When a notification is added/updated: ForegroundServiceNotificationListener updates the relevant notification's appOps Test: atest NotificationEntryManagerTest NotificationDataTest Test: atest ForegroundServiceControllerTest Change-Id: I3af4a2cf599d3eba7a0ba6006b3919730e5e658a
This commit is contained in:
@@ -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<ForegroundServicesUserState> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Integer> activeOps = mForegroundServiceController.getAppOps(
|
||||
sbn.getUserId(),
|
||||
sbn.getPackageName());
|
||||
if (activeOps != null) {
|
||||
synchronized (entry.mActiveAppOps) {
|
||||
entry.mActiveAppOps.clear();
|
||||
entry.mActiveAppOps.addAll(activeOps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<Integer> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -130,7 +130,7 @@ public final class NotificationEntry {
|
||||
private Throwable mDebugThrowable;
|
||||
public CharSequence remoteInputTextWhenReset;
|
||||
public long lastRemoteInputSent = NOT_LAUNCHED_YET;
|
||||
public ArraySet<Integer> mActiveAppOps = new ArraySet<>(3);
|
||||
public final ArraySet<Integer> mActiveAppOps = new ArraySet<>(3);
|
||||
public CharSequence headsUpStatusBarText;
|
||||
public CharSequence headsUpStatusBarTextPublic;
|
||||
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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<NotificationEntryListener> 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";
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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<Integer> 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<Integer> 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++;
|
||||
|
||||
|
||||
@@ -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<Integer> 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<Integer> 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 {
|
||||
|
||||
Reference in New Issue
Block a user