Factors out notification listening from ForegroundServiceController.
This change introduces the ForegroundServiceNotificationListener
component, which contains the logic formerly in
ForegroundServiceController for updating its state in response to
notification events. ForegroundServiceNotificationListener adds a
standard NotificationEntryListener to the NotificationEntryManager,
allowing us to remove the explicit calls from NotificationEntryManager;
splitting this out to its own class prevents us from introducing a
circular dependency since NotificationEntryManager still needs to use
the query methods on ForegroundServiceController.
Test: atest SystemUITests, manual
Change-Id: Iec72aa3a9fd90e3f0079db3b2a3c4f1882e59731
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index a8d3763..9a7a9bf 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -272,6 +272,7 @@
Lazy<NotificationAlertingManager> mNotificationAlertingManager;
@Inject Lazy<SensorPrivacyManager> mSensorPrivacyManager;
@Inject Lazy<AutoHideController> mAutoHideController;
+ @Inject Lazy<ForegroundServiceNotificationListener> mForegroundServiceNotificationListener;
@Inject @Named(BG_LOOPER_NAME) Lazy<Looper> mBgLooper;
@Inject @Named(BG_HANDLER_NAME) Lazy<Handler> mBgHandler;
@Inject @Named(MAIN_HANDLER_NAME) Lazy<Handler> mMainHandler;
@@ -444,6 +445,8 @@
mProviders.put(BubbleController.class, mBubbleController::get);
mProviders.put(NotificationEntryManager.class, mNotificationEntryManager::get);
mProviders.put(NotificationAlertingManager.class, mNotificationAlertingManager::get);
+ mProviders.put(ForegroundServiceNotificationListener.class,
+ mForegroundServiceNotificationListener::get);
// TODO(b/118592525): to support multi-display , we start to add something which is
// per-display, while others may be global. I think it's time to add
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
index 5c24838..df0d787 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
@@ -15,54 +15,38 @@
package com.android.systemui;
import android.annotation.Nullable;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.os.Bundle;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
-import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.Log;
import android.util.SparseArray;
import com.android.internal.messages.nano.SystemMessageProto;
-import java.util.Arrays;
-
import javax.inject.Inject;
import javax.inject.Singleton;
/**
- * Foreground service controller, a/k/a Dianne's Dungeon.
+ * Tracks state of foreground services and notifications related to foreground services per user.
*/
@Singleton
public class ForegroundServiceController {
- // shelf life of foreground services before they go bad
- private static final long FG_SERVICE_GRACE_MILLIS = 5000;
-
- private static final String TAG = "FgServiceController";
- private static final boolean DBG = false;
-
- private final Context mContext;
- private final SparseArray<UserServices> mUserServices = new SparseArray<>();
+ private final SparseArray<ForegroundServicesUserState> mUserServices = new SparseArray<>();
private final Object mMutex = new Object();
@Inject
- public ForegroundServiceController(Context context) {
- mContext = context;
+ public ForegroundServiceController() {
}
/**
* @return true if this user has services missing notifications and therefore needs a
* disclosure notification.
*/
- public boolean isDungeonNeededForUser(int userId) {
+ public boolean isDisclosureNeededForUser(int userId) {
synchronized (mMutex) {
- final UserServices services = mUserServices.get(userId);
+ final ForegroundServicesUserState services = mUserServices.get(userId);
if (services == null) return false;
- return services.isDungeonNeeded();
+ return services.isDisclosureNeeded();
}
}
@@ -72,7 +56,7 @@
*/
public boolean isSystemAlertWarningNeeded(int userId, String pkg) {
synchronized (mMutex) {
- final UserServices services = mUserServices.get(userId);
+ final ForegroundServicesUserState services = mUserServices.get(userId);
if (services == null) return false;
return services.getStandardLayoutKey(pkg) == null;
}
@@ -85,7 +69,7 @@
@Nullable
public String getStandardLayoutKey(int userId, String pkg) {
synchronized (mMutex) {
- final UserServices services = mUserServices.get(userId);
+ final ForegroundServicesUserState services = mUserServices.get(userId);
if (services == null) return null;
return services.getStandardLayoutKey(pkg);
}
@@ -97,7 +81,7 @@
@Nullable
public ArraySet<Integer> getAppOps(int userId, String pkg) {
synchronized (mMutex) {
- final UserServices services = mUserServices.get(userId);
+ final ForegroundServicesUserState services = mUserServices.get(userId);
if (services == null) {
return null;
}
@@ -112,9 +96,9 @@
public void onAppOpChanged(int code, int uid, String packageName, boolean active) {
int userId = UserHandle.getUserId(uid);
synchronized (mMutex) {
- UserServices userServices = mUserServices.get(userId);
+ ForegroundServicesUserState userServices = mUserServices.get(userId);
if (userServices == null) {
- userServices = new UserServices();
+ userServices = new ForegroundServicesUserState();
mUserServices.put(userId, userServices);
}
if (active) {
@@ -126,77 +110,35 @@
}
/**
- * @param sbn notification that was just posted
- * @param importance
+ * Looks up the {@link ForegroundServicesUserState} for the given {@code userId}, then performs
+ * the given {@link UserStateUpdateCallback} on it. If no state exists for the user ID, creates
+ * a new one if {@code createIfNotFound} is true, then performs the update on the new state.
+ * If {@code createIfNotFound} is false, no update is performed.
+ *
+ * @return false if no user state was found and none was created; true otherwise.
*/
- public void addNotification(StatusBarNotification sbn, int importance) {
- updateNotification(sbn, importance);
- }
-
- /**
- * @param sbn notification that was just removed
- */
- public boolean removeNotification(StatusBarNotification sbn) {
+ boolean updateUserState(int userId,
+ UserStateUpdateCallback updateCallback,
+ boolean createIfNotFound) {
synchronized (mMutex) {
- final UserServices userServices = mUserServices.get(sbn.getUserId());
- if (userServices == null) {
- if (DBG) {
- Log.w(TAG, String.format(
- "user %d with no known notifications got removeNotification for %s",
- sbn.getUserId(), sbn));
+ ForegroundServicesUserState userState = mUserServices.get(userId);
+ if (userState == null) {
+ if (createIfNotFound) {
+ userState = new ForegroundServicesUserState();
+ mUserServices.put(userId, userState);
+ } else {
+ return false;
}
- return false;
}
- if (isDungeonNotification(sbn)) {
- // if you remove the dungeon entirely, we take that to mean there are
- // no running services
- userServices.setRunningServices(null, 0);
- return true;
- } else {
- // this is safe to call on any notification, not just FLAG_FOREGROUND_SERVICE
- return userServices.removeNotification(sbn.getPackageName(), sbn.getKey());
- }
+ return updateCallback.updateUserState(userState);
}
}
/**
- * @param sbn notification that was just changed in some way
+ * @return true if {@code sbn} is the system-provided disclosure notification containing the
+ * list of running foreground services.
*/
- public void updateNotification(StatusBarNotification sbn, int newImportance) {
- synchronized (mMutex) {
- UserServices userServices = mUserServices.get(sbn.getUserId());
- if (userServices == null) {
- userServices = new UserServices();
- mUserServices.put(sbn.getUserId(), userServices);
- }
-
- if (isDungeonNotification(sbn)) {
- final Bundle extras = sbn.getNotification().extras;
- if (extras != null) {
- final String[] svcs = extras.getStringArray(Notification.EXTRA_FOREGROUND_APPS);
- userServices.setRunningServices(svcs, sbn.getNotification().when);
- }
- } else {
- userServices.removeNotification(sbn.getPackageName(), sbn.getKey());
- if (0 != (sbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE)) {
- if (newImportance > NotificationManager.IMPORTANCE_MIN) {
- userServices.addImportantNotification(sbn.getPackageName(), sbn.getKey());
- }
- final Notification.Builder builder = Notification.Builder.recoverBuilder(
- mContext, sbn.getNotification());
- if (builder.usesStandardHeader()) {
- userServices.addStandardLayoutNotification(
- sbn.getPackageName(), sbn.getKey());
- }
- }
- }
- }
- }
-
- /**
- * @return true if sbn is the system-provided "dungeon" (list of running foreground services).
- */
- public boolean isDungeonNotification(StatusBarNotification sbn) {
+ public boolean isDisclosureNotification(StatusBarNotification sbn) {
return sbn.getId() == SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES
&& sbn.getTag() == null
&& sbn.getPackageName().equals("android");
@@ -212,125 +154,19 @@
}
/**
- * Struct to track relevant packages and notifications for a userid's foreground services.
+ * Callback provided to {@link #updateUserState(int, UserStateUpdateCallback, boolean)}
+ * to perform the update.
*/
- private static class UserServices {
- private String[] mRunning = null;
- private long mServiceStartTime = 0;
- // package -> sufficiently important posted notification keys
- private ArrayMap<String, ArraySet<String>> mImportantNotifications = new ArrayMap<>(1);
- // package -> standard layout posted notification keys
- private ArrayMap<String, ArraySet<String>> mStandardLayoutNotifications = new ArrayMap<>(1);
+ interface UserStateUpdateCallback {
+ /**
+ * Perform update operations on the provided {@code userState}.
+ *
+ * @return true if the update succeeded.
+ */
+ boolean updateUserState(ForegroundServicesUserState userState);
- // package -> app ops
- private ArrayMap<String, ArraySet<Integer>> mAppOps = new ArrayMap<>(1);
-
- public void setRunningServices(String[] pkgs, long serviceStartTime) {
- mRunning = pkgs != null ? Arrays.copyOf(pkgs, pkgs.length) : null;
- mServiceStartTime = serviceStartTime;
- }
-
- public void addOp(String pkg, int op) {
- if (mAppOps.get(pkg) == null) {
- mAppOps.put(pkg, new ArraySet<>(3));
- }
- mAppOps.get(pkg).add(op);
- }
-
- public boolean removeOp(String pkg, int op) {
- final boolean found;
- final ArraySet<Integer> keys = mAppOps.get(pkg);
- if (keys == null) {
- found = false;
- } else {
- found = keys.remove(op);
- if (keys.size() == 0) {
- mAppOps.remove(pkg);
- }
- }
- return found;
- }
-
- public void addImportantNotification(String pkg, String key) {
- addNotification(mImportantNotifications, pkg, key);
- }
-
- public boolean removeImportantNotification(String pkg, String key) {
- return removeNotification(mImportantNotifications, pkg, key);
- }
-
- public void addStandardLayoutNotification(String pkg, String key) {
- addNotification(mStandardLayoutNotifications, pkg, key);
- }
-
- public boolean removeStandardLayoutNotification(String pkg, String key) {
- return removeNotification(mStandardLayoutNotifications, pkg, key);
- }
-
- public boolean removeNotification(String pkg, String key) {
- boolean removed = false;
- removed |= removeImportantNotification(pkg, key);
- removed |= removeStandardLayoutNotification(pkg, key);
- return removed;
- }
-
- public void addNotification(ArrayMap<String, ArraySet<String>> map, String pkg,
- String key) {
- if (map.get(pkg) == null) {
- map.put(pkg, new ArraySet<>());
- }
- map.get(pkg).add(key);
- }
-
- public boolean removeNotification(ArrayMap<String, ArraySet<String>> map,
- String pkg, String key) {
- final boolean found;
- final ArraySet<String> keys = map.get(pkg);
- if (keys == null) {
- found = false;
- } else {
- found = keys.remove(key);
- if (keys.size() == 0) {
- map.remove(pkg);
- }
- }
- return found;
- }
-
- public boolean isDungeonNeeded() {
- if (mRunning != null
- && System.currentTimeMillis() - mServiceStartTime >= FG_SERVICE_GRACE_MILLIS) {
-
- for (String pkg : mRunning) {
- final ArraySet<String> set = mImportantNotifications.get(pkg);
- if (set == null || set.size() == 0) {
- return true;
- }
- }
- }
- return false;
- }
-
- public ArraySet<Integer> getFeatures(String pkg) {
- return mAppOps.get(pkg);
- }
-
- public String getStandardLayoutKey(String pkg) {
- final ArraySet<String> set = mStandardLayoutNotifications.get(pkg);
- if (set == null || set.size() == 0) {
- return null;
- }
- return set.valueAt(0);
- }
-
- @Override
- public String toString() {
- return "UserServices{"
- + "mRunning=" + Arrays.toString(mRunning)
- + ", mServiceStartTime=" + mServiceStartTime
- + ", mImportantNotifications=" + mImportantNotifications
- + ", mStandardLayoutNotifications=" + mStandardLayoutNotifications
- + '}';
+ /** Called if the state was not found and was not created. */
+ default void userStateNotFound(int userId) {
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
new file mode 100644
index 0000000..151a6b0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.os.Bundle;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/** Updates foreground service notification state in response to notification data events. */
+@Singleton
+public class ForegroundServiceNotificationListener {
+
+ private static final String TAG = "FgServiceController";
+ private static final boolean DBG = false;
+
+ private final Context mContext;
+ private final ForegroundServiceController mForegroundServiceController;
+
+ @Inject
+ public ForegroundServiceNotificationListener(Context context,
+ ForegroundServiceController foregroundServiceController,
+ NotificationEntryManager notificationEntryManager) {
+ mContext = context;
+ mForegroundServiceController = foregroundServiceController;
+ notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
+ @Override
+ public void onPendingEntryAdded(NotificationData.Entry entry) {
+ addNotification(entry.notification, entry.importance);
+ }
+
+ @Override
+ public void onEntryUpdated(NotificationData.Entry entry) {
+ updateNotification(entry.notification, entry.importance);
+ }
+
+ @Override
+ public void onEntryRemoved(
+ NotificationData.Entry entry,
+ String key,
+ StatusBarNotification old,
+ NotificationVisibility visibility,
+ boolean lifetimeExtended,
+ boolean removedByUser) {
+ if (entry != null && !lifetimeExtended) {
+ removeNotification(entry.notification);
+ }
+ }
+ });
+ }
+
+ /**
+ * @param sbn notification that was just posted
+ */
+ private void addNotification(StatusBarNotification sbn, int importance) {
+ updateNotification(sbn, importance);
+ }
+
+ /**
+ * @param sbn notification that was just removed
+ */
+ private void removeNotification(StatusBarNotification sbn) {
+ mForegroundServiceController.updateUserState(
+ sbn.getUserId(),
+ new ForegroundServiceController.UserStateUpdateCallback() {
+ @Override
+ public boolean updateUserState(ForegroundServicesUserState userState) {
+ if (mForegroundServiceController.isDisclosureNotification(sbn)) {
+ // if you remove the dungeon entirely, we take that to mean there are
+ // no running services
+ userState.setRunningServices(null, 0);
+ return true;
+ } else {
+ // this is safe to call on any notification, not just
+ // FLAG_FOREGROUND_SERVICE
+ return userState.removeNotification(sbn.getPackageName(), sbn.getKey());
+ }
+ }
+
+ @Override
+ public void userStateNotFound(int userId) {
+ if (DBG) {
+ Log.w(TAG, String.format(
+ "user %d with no known notifications got removeNotification "
+ + "for %s",
+ sbn.getUserId(), sbn));
+ }
+ }
+ },
+ false /* don't create */);
+ }
+
+ /**
+ * @param sbn notification that was just changed in some way
+ */
+ private void updateNotification(StatusBarNotification sbn, int newImportance) {
+ mForegroundServiceController.updateUserState(
+ sbn.getUserId(),
+ userState -> {
+ if (mForegroundServiceController.isDisclosureNotification(sbn)) {
+ final Bundle extras = sbn.getNotification().extras;
+ if (extras != null) {
+ final String[] svcs = extras.getStringArray(
+ Notification.EXTRA_FOREGROUND_APPS);
+ userState.setRunningServices(svcs, sbn.getNotification().when);
+ }
+ } else {
+ userState.removeNotification(sbn.getPackageName(), sbn.getKey());
+ if (0 != (sbn.getNotification().flags
+ & Notification.FLAG_FOREGROUND_SERVICE)) {
+ if (newImportance > NotificationManager.IMPORTANCE_MIN) {
+ userState.addImportantNotification(sbn.getPackageName(),
+ sbn.getKey());
+ }
+ final Notification.Builder builder =
+ Notification.Builder.recoverBuilder(
+ mContext, sbn.getNotification());
+ if (builder.usesStandardHeader()) {
+ userState.addStandardLayoutNotification(
+ sbn.getPackageName(), sbn.getKey());
+ }
+ }
+ }
+ return true;
+ },
+ true /* create if not found */);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServicesUserState.java b/packages/SystemUI/src/com/android/systemui/ForegroundServicesUserState.java
new file mode 100644
index 0000000..a8ae654
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServicesUserState.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import java.util.Arrays;
+
+/**
+ * Struct to track relevant packages and notifications for a userid's foreground services.
+ */
+class ForegroundServicesUserState {
+ // shelf life of foreground services before they go bad
+ private static final long FG_SERVICE_GRACE_MILLIS = 5000;
+
+ private String[] mRunning = null;
+ private long mServiceStartTime = 0;
+ // package -> sufficiently important posted notification keys
+ private ArrayMap<String, ArraySet<String>> mImportantNotifications = new ArrayMap<>(1);
+ // package -> standard layout posted notification keys
+ private ArrayMap<String, ArraySet<String>> mStandardLayoutNotifications = new ArrayMap<>(1);
+
+ // package -> app ops
+ private ArrayMap<String, ArraySet<Integer>> mAppOps = new ArrayMap<>(1);
+
+ public void setRunningServices(String[] pkgs, long serviceStartTime) {
+ mRunning = pkgs != null ? Arrays.copyOf(pkgs, pkgs.length) : null;
+ mServiceStartTime = serviceStartTime;
+ }
+
+ public void addOp(String pkg, int op) {
+ if (mAppOps.get(pkg) == null) {
+ mAppOps.put(pkg, new ArraySet<>(3));
+ }
+ mAppOps.get(pkg).add(op);
+ }
+
+ public boolean removeOp(String pkg, int op) {
+ final boolean found;
+ final ArraySet<Integer> keys = mAppOps.get(pkg);
+ if (keys == null) {
+ found = false;
+ } else {
+ found = keys.remove(op);
+ if (keys.size() == 0) {
+ mAppOps.remove(pkg);
+ }
+ }
+ return found;
+ }
+
+ public void addImportantNotification(String pkg, String key) {
+ addNotification(mImportantNotifications, pkg, key);
+ }
+
+ public boolean removeImportantNotification(String pkg, String key) {
+ return removeNotification(mImportantNotifications, pkg, key);
+ }
+
+ public void addStandardLayoutNotification(String pkg, String key) {
+ addNotification(mStandardLayoutNotifications, pkg, key);
+ }
+
+ public boolean removeStandardLayoutNotification(String pkg, String key) {
+ return removeNotification(mStandardLayoutNotifications, pkg, key);
+ }
+
+ public boolean removeNotification(String pkg, String key) {
+ boolean removed = false;
+ removed |= removeImportantNotification(pkg, key);
+ removed |= removeStandardLayoutNotification(pkg, key);
+ return removed;
+ }
+
+ public void addNotification(ArrayMap<String, ArraySet<String>> map, String pkg,
+ String key) {
+ if (map.get(pkg) == null) {
+ map.put(pkg, new ArraySet<>());
+ }
+ map.get(pkg).add(key);
+ }
+
+ public boolean removeNotification(ArrayMap<String, ArraySet<String>> map,
+ String pkg, String key) {
+ final boolean found;
+ final ArraySet<String> keys = map.get(pkg);
+ if (keys == null) {
+ found = false;
+ } else {
+ found = keys.remove(key);
+ if (keys.size() == 0) {
+ map.remove(pkg);
+ }
+ }
+ return found;
+ }
+
+ public boolean isDisclosureNeeded() {
+ if (mRunning != null
+ && System.currentTimeMillis() - mServiceStartTime
+ >= FG_SERVICE_GRACE_MILLIS) {
+
+ for (String pkg : mRunning) {
+ final ArraySet<String> set = mImportantNotifications.get(pkg);
+ if (set == null || set.size() == 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public ArraySet<Integer> getFeatures(String pkg) {
+ return mAppOps.get(pkg);
+ }
+
+ public String getStandardLayoutKey(String pkg) {
+ final ArraySet<String> set = mStandardLayoutNotifications.get(pkg);
+ if (set == null || set.size() == 0) {
+ return null;
+ }
+ return set.valueAt(0);
+ }
+
+ @Override
+ public String toString() {
+ return "UserServices{"
+ + "mRunning=" + Arrays.toString(mRunning)
+ + ", mServiceStartTime=" + mServiceStartTime
+ + ", mImportantNotifications=" + mImportantNotifications
+ + ", mStandardLayoutNotifications=" + mStandardLayoutNotifications
+ + '}';
+ }
+}
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 e0fa723..cdf9a54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -344,8 +344,6 @@
extender.setShouldManageLifetime(entry, false /* shouldManage */);
}
- mForegroundServiceController.removeNotification(entry.notification);
-
if (entry.rowExists()) {
entry.removeRow();
mListContainer.cleanUpViewStateForEntry(entry);
@@ -463,9 +461,6 @@
NotificationData.Entry entry = createNotificationEntry(notification, ranking);
abortExistingInflation(key);
- mForegroundServiceController.addNotification(notification,
- mNotificationData.getImportance(key));
-
mPendingNotifications.put(key, entry);
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onPendingEntryAdded(entry);
@@ -527,9 +522,6 @@
getRowBinder().inflateViews(entry, () -> performRemoveNotification(notification),
mNotificationData.get(entry.key) != null);
- mForegroundServiceController.updateNotification(notification,
- mNotificationData.getImportance(key));
-
updateNotifications();
if (!notification.isClearable()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
index 5e99c38..700382a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
@@ -117,8 +117,8 @@
return true;
}
- if (getFsc().isDungeonNotification(sbn)
- && !getFsc().isDungeonNeededForUser(sbn.getUserId())) {
+ if (getFsc().isDisclosureNotification(sbn)
+ && !getFsc().isDisclosureNeededForUser(sbn.getUserId())) {
// this is a foreground-service disclosure for a user that does not need to show one
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 7b7bcb4..b9372e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -43,6 +43,7 @@
import com.android.internal.widget.MessagingMessage;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dependency;
+import com.android.systemui.ForegroundServiceNotificationListener;
import com.android.systemui.InitController;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
@@ -228,6 +229,10 @@
mVisualStabilityManager.setUpWithPresenter(this);
gutsManager.setUpWithPresenter(this,
notifListContainer, mCheckSaveListener, mOnSettingsClickListener);
+ // ForegroundServiceControllerListener adds its listener in its constructor
+ // but we need to request it here in order for it to be instantiated.
+ // TODO: figure out how to do this correctly once Dependency.get() is gone.
+ Dependency.get(ForegroundServiceNotificationListener.class);
onUserSwitched(mLockscreenUserManager.getCurrentUserId());
});
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index d8b473b..199a3a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.annotation.UserIdInt;
@@ -35,197 +36,95 @@
import android.widget.RemoteViews;
import com.android.internal.messages.nano.SystemMessageProto;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ForegroundServiceControllerTest extends SysuiTestCase {
- public static @UserIdInt int USERID_ONE = 10; // UserManagerService.MIN_USER_ID;
- public static @UserIdInt int USERID_TWO = USERID_ONE + 1;
+ @UserIdInt private static final int USERID_ONE = 10; // UserManagerService.MIN_USER_ID;
+ @UserIdInt private static final int USERID_TWO = USERID_ONE + 1;
- private ForegroundServiceController fsc;
+ private ForegroundServiceController mFsc;
+ private ForegroundServiceNotificationListener mListener;
+ private NotificationEntryListener mEntryListener;
@Before
public void setUp() throws Exception {
- fsc = new ForegroundServiceController(mContext);
- }
-
- @Test
- public void testNotificationCRUD_dungeon() {
- StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, "com.example.app1");
- StatusBarNotification sbn_user2_app2_fg = makeMockFgSBN(USERID_TWO, "com.example.app2");
- StatusBarNotification sbn_user1_app3_fg = makeMockFgSBN(USERID_ONE, "com.example.app3");
- StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
- 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
- StatusBarNotification sbn_user2_app1 = makeMockSBN(USERID_TWO, "com.example.app1",
- 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
-
- assertFalse(fsc.removeNotification(sbn_user1_app3_fg));
- assertFalse(fsc.removeNotification(sbn_user2_app2_fg));
- assertFalse(fsc.removeNotification(sbn_user1_app1_fg));
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.removeNotification(sbn_user2_app1));
-
- fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
- fsc.addNotification(sbn_user2_app2_fg, NotificationManager.IMPORTANCE_DEFAULT);
- fsc.addNotification(sbn_user1_app3_fg, NotificationManager.IMPORTANCE_DEFAULT);
- fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
- fsc.addNotification(sbn_user2_app1, NotificationManager.IMPORTANCE_DEFAULT);
-
- // these are never added to the tracker
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.removeNotification(sbn_user2_app1));
-
- fsc.updateNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
- fsc.updateNotification(sbn_user2_app1, NotificationManager.IMPORTANCE_DEFAULT);
- // should still not be there
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.removeNotification(sbn_user2_app1));
-
- fsc.updateNotification(sbn_user2_app2_fg, NotificationManager.IMPORTANCE_DEFAULT);
- fsc.updateNotification(sbn_user1_app3_fg, NotificationManager.IMPORTANCE_DEFAULT);
- fsc.updateNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
-
- assertTrue(fsc.removeNotification(sbn_user1_app3_fg));
- assertFalse(fsc.removeNotification(sbn_user1_app3_fg));
-
- assertTrue(fsc.removeNotification(sbn_user2_app2_fg));
- assertFalse(fsc.removeNotification(sbn_user2_app2_fg));
-
- assertTrue(fsc.removeNotification(sbn_user1_app1_fg));
- assertFalse(fsc.removeNotification(sbn_user1_app1_fg));
-
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.removeNotification(sbn_user2_app1));
- }
-
- @Test
- public void testNotificationCRUD_stdLayout() {
- StatusBarNotification sbn_user1_app1_fg =
- makeMockFgSBN(USERID_ONE, "com.example.app1", 0, true);
- StatusBarNotification sbn_user2_app2_fg =
- makeMockFgSBN(USERID_TWO, "com.example.app2", 1, true);
- StatusBarNotification sbn_user1_app3_fg =
- makeMockFgSBN(USERID_ONE, "com.example.app3", 2, true);
- StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
- 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
- StatusBarNotification sbn_user2_app1 = makeMockSBN(USERID_TWO, "com.example.app1",
- 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
-
- assertFalse(fsc.removeNotification(sbn_user1_app3_fg));
- assertFalse(fsc.removeNotification(sbn_user2_app2_fg));
- assertFalse(fsc.removeNotification(sbn_user1_app1_fg));
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.removeNotification(sbn_user2_app1));
-
- fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
- fsc.addNotification(sbn_user2_app2_fg, NotificationManager.IMPORTANCE_MIN);
- fsc.addNotification(sbn_user1_app3_fg, NotificationManager.IMPORTANCE_MIN);
- fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN);
- fsc.addNotification(sbn_user2_app1, NotificationManager.IMPORTANCE_MIN);
-
- // these are never added to the tracker
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.removeNotification(sbn_user2_app1));
-
- fsc.updateNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN);
- fsc.updateNotification(sbn_user2_app1, NotificationManager.IMPORTANCE_MIN);
- // should still not be there
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.removeNotification(sbn_user2_app1));
-
- fsc.updateNotification(sbn_user2_app2_fg, NotificationManager.IMPORTANCE_MIN);
- fsc.updateNotification(sbn_user1_app3_fg, NotificationManager.IMPORTANCE_MIN);
- fsc.updateNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
-
- assertTrue(fsc.removeNotification(sbn_user1_app3_fg));
- assertFalse(fsc.removeNotification(sbn_user1_app3_fg));
-
- assertTrue(fsc.removeNotification(sbn_user2_app2_fg));
- assertFalse(fsc.removeNotification(sbn_user2_app2_fg));
-
- assertTrue(fsc.removeNotification(sbn_user1_app1_fg));
- assertFalse(fsc.removeNotification(sbn_user1_app1_fg));
-
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.removeNotification(sbn_user2_app1));
+ mFsc = new ForegroundServiceController();
+ NotificationEntryManager notificationEntryManager = mock(NotificationEntryManager.class);
+ mListener = new ForegroundServiceNotificationListener(
+ mContext, mFsc, notificationEntryManager);
+ ArgumentCaptor<NotificationEntryListener> entryListenerCaptor =
+ ArgumentCaptor.forClass(NotificationEntryListener.class);
+ verify(notificationEntryManager).addNotificationEntryListener(
+ entryListenerCaptor.capture());
+ mEntryListener = entryListenerCaptor.getValue();
}
@Test
public void testAppOpsCRUD() {
// no crash on remove that doesn't exist
- fsc.onAppOpChanged(9, 1000, "pkg1", false);
- assertNull(fsc.getAppOps(0, "pkg1"));
+ mFsc.onAppOpChanged(9, 1000, "pkg1", false);
+ assertNull(mFsc.getAppOps(0, "pkg1"));
// multiuser & multipackage
- fsc.onAppOpChanged(8, 50, "pkg1", true);
- fsc.onAppOpChanged(1, 60, "pkg3", true);
- fsc.onAppOpChanged(7, 500000, "pkg2", true);
+ mFsc.onAppOpChanged(8, 50, "pkg1", true);
+ mFsc.onAppOpChanged(1, 60, "pkg3", true);
+ mFsc.onAppOpChanged(7, 500000, "pkg2", true);
- assertEquals(1, fsc.getAppOps(0, "pkg1").size());
- assertTrue(fsc.getAppOps(0, "pkg1").contains(8));
+ assertEquals(1, mFsc.getAppOps(0, "pkg1").size());
+ assertTrue(mFsc.getAppOps(0, "pkg1").contains(8));
- assertEquals(1, fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size());
- assertTrue(fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7));
+ assertEquals(1, mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size());
+ assertTrue(mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7));
- assertEquals(1, fsc.getAppOps(0, "pkg3").size());
- assertTrue(fsc.getAppOps(0, "pkg3").contains(1));
+ assertEquals(1, mFsc.getAppOps(0, "pkg3").size());
+ assertTrue(mFsc.getAppOps(0, "pkg3").contains(1));
// multiple ops for the same package
- fsc.onAppOpChanged(9, 50, "pkg1", true);
- fsc.onAppOpChanged(5, 50, "pkg1", true);
+ mFsc.onAppOpChanged(9, 50, "pkg1", true);
+ mFsc.onAppOpChanged(5, 50, "pkg1", true);
- assertEquals(3, fsc.getAppOps(0, "pkg1").size());
- assertTrue(fsc.getAppOps(0, "pkg1").contains(8));
- assertTrue(fsc.getAppOps(0, "pkg1").contains(9));
- assertTrue(fsc.getAppOps(0, "pkg1").contains(5));
+ assertEquals(3, mFsc.getAppOps(0, "pkg1").size());
+ assertTrue(mFsc.getAppOps(0, "pkg1").contains(8));
+ assertTrue(mFsc.getAppOps(0, "pkg1").contains(9));
+ assertTrue(mFsc.getAppOps(0, "pkg1").contains(5));
- assertEquals(1, fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size());
- assertTrue(fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7));
+ assertEquals(1, mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size());
+ assertTrue(mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7));
// remove one of the multiples
- fsc.onAppOpChanged(9, 50, "pkg1", false);
- assertEquals(2, fsc.getAppOps(0, "pkg1").size());
- assertTrue(fsc.getAppOps(0, "pkg1").contains(8));
- assertTrue(fsc.getAppOps(0, "pkg1").contains(5));
+ mFsc.onAppOpChanged(9, 50, "pkg1", false);
+ assertEquals(2, mFsc.getAppOps(0, "pkg1").size());
+ assertTrue(mFsc.getAppOps(0, "pkg1").contains(8));
+ assertTrue(mFsc.getAppOps(0, "pkg1").contains(5));
// remove last op
- fsc.onAppOpChanged(1, 60, "pkg3", false);
- assertNull(fsc.getAppOps(0, "pkg3"));
+ mFsc.onAppOpChanged(1, 60, "pkg3", false);
+ assertNull(mFsc.getAppOps(0, "pkg3"));
}
@Test
- public void testDungeonPredicate() {
+ public void testDisclosurePredicate() {
StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
- StatusBarNotification sbn_user1_dungeon = makeMockSBN(USERID_ONE, "android",
+ StatusBarNotification sbn_user1_disclosure = makeMockSBN(USERID_ONE, "android",
SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES,
null, Notification.FLAG_NO_CLEAR);
- assertTrue(fsc.isDungeonNotification(sbn_user1_dungeon));
- assertFalse(fsc.isDungeonNotification(sbn_user1_app1));
+ assertTrue(mFsc.isDisclosureNotification(sbn_user1_disclosure));
+ assertFalse(mFsc.isDisclosureNotification(sbn_user1_app1));
}
@Test
- public void testDungeonCRUD() {
- StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
- 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
- StatusBarNotification sbn_user1_dungeon = makeMockSBN(USERID_ONE, "android",
- SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES,
- null, Notification.FLAG_NO_CLEAR);
-
- fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
- fsc.addNotification(sbn_user1_dungeon, NotificationManager.IMPORTANCE_DEFAULT);
-
- fsc.removeNotification(sbn_user1_dungeon);
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- }
-
- @Test
- public void testNeedsDungeonAfterRemovingUnrelatedNotification() {
+ public void testNeedsDisclosureAfterRemovingUnrelatedNotification() {
final String PKG1 = "com.example.app100";
StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, PKG1,
@@ -233,21 +132,21 @@
StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, PKG1);
// first add a normal notification
- fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
+ entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
// nothing required yet
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
// now the app starts a fg service
- fsc.addNotification(makeMockDungeon(USERID_ONE, new String[]{ PKG1 }),
+ entryAdded(makeMockDisclosure(USERID_ONE, new String[]{PKG1}),
NotificationManager.IMPORTANCE_DEFAULT);
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
// add the fg notification
- fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE)); // app1 has got it covered
+ entryAdded(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE)); // app1 has got it covered
// remove the boring notification
- fsc.removeNotification(sbn_user1_app1);
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE)); // app1 has STILL got it covered
- assertTrue(fsc.removeNotification(sbn_user1_app1_fg));
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
+ entryRemoved(sbn_user1_app1);
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE)); // app1 has STILL got it covered
+ entryRemoved(sbn_user1_app1_fg);
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
}
@Test
@@ -257,115 +156,117 @@
StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, PKG1,
5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
- fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
+ entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
// no services are "running"
- fsc.addNotification(makeMockDungeon(USERID_ONE, null),
+ entryAdded(makeMockDisclosure(USERID_ONE, null),
NotificationManager.IMPORTANCE_DEFAULT);
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
- fsc.updateNotification(makeMockDungeon(USERID_ONE, new String[]{PKG1}),
+ entryUpdated(makeMockDisclosure(USERID_ONE, new String[]{PKG1}),
NotificationManager.IMPORTANCE_DEFAULT);
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
// switch to different package
- fsc.updateNotification(makeMockDungeon(USERID_ONE, new String[]{PKG2}),
+ entryUpdated(makeMockDisclosure(USERID_ONE, new String[]{PKG2}),
NotificationManager.IMPORTANCE_DEFAULT);
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
- fsc.updateNotification(makeMockDungeon(USERID_TWO, new String[]{PKG1}),
+ entryUpdated(makeMockDisclosure(USERID_TWO, new String[]{PKG1}),
NotificationManager.IMPORTANCE_DEFAULT);
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
- assertTrue(fsc.isDungeonNeededForUser(USERID_TWO)); // finally user2 needs one too
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_TWO)); // finally user2 needs one too
- fsc.updateNotification(makeMockDungeon(USERID_ONE, new String[]{PKG2, PKG1}),
+ entryUpdated(makeMockDisclosure(USERID_ONE, new String[]{PKG2, PKG1}),
NotificationManager.IMPORTANCE_DEFAULT);
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
- assertTrue(fsc.isDungeonNeededForUser(USERID_TWO));
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_TWO));
- fsc.removeNotification(makeMockDungeon(USERID_ONE, null /*unused*/));
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
- assertTrue(fsc.isDungeonNeededForUser(USERID_TWO));
+ entryRemoved(makeMockDisclosure(USERID_ONE, null /*unused*/));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_TWO));
- fsc.removeNotification(makeMockDungeon(USERID_TWO, null /*unused*/));
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ entryRemoved(makeMockDisclosure(USERID_TWO, null /*unused*/));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
}
@Test
- public void testDungeonBasic() {
+ public void testDisclosureBasic() {
final String PKG1 = "com.example.app0";
StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, PKG1,
5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, PKG1);
- fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT); // not fg
- fsc.addNotification(makeMockDungeon(USERID_ONE, new String[]{ PKG1 }),
+ entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT); // not fg
+ entryAdded(makeMockDisclosure(USERID_ONE, new String[]{PKG1}),
NotificationManager.IMPORTANCE_DEFAULT);
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
- fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE)); // app1 has got it covered
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
+ entryAdded(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE)); // app1 has got it covered
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
// let's take out the other notification and see what happens.
- fsc.removeNotification(sbn_user1_app1);
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE)); // still covered by sbn_user1_app1_fg
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ entryRemoved(sbn_user1_app1);
+ assertFalse(
+ mFsc.isDisclosureNeededForUser(USERID_ONE)); // still covered by sbn_user1_app1_fg
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
// let's attempt to downgrade the notification from FLAG_FOREGROUND and see what we get
StatusBarNotification sbn_user1_app1_fg_sneaky = makeMockFgSBN(USERID_ONE, PKG1);
sbn_user1_app1_fg_sneaky.getNotification().flags = 0;
- fsc.updateNotification(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_DEFAULT);
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ entryUpdated(sbn_user1_app1_fg_sneaky,
+ NotificationManager.IMPORTANCE_DEFAULT);
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
// ok, ok, we'll put it back
sbn_user1_app1_fg_sneaky.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
- fsc.updateNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ entryUpdated(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
- assertTrue(fsc.removeNotification(sbn_user1_app1_fg_sneaky));
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ entryRemoved(sbn_user1_app1_fg_sneaky);
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
// now let's test an upgrade
- fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
sbn_user1_app1.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
- fsc.updateNotification(sbn_user1_app1,
+ entryUpdated(sbn_user1_app1,
NotificationManager.IMPORTANCE_DEFAULT); // this is now a fg notification
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
// remove it, make sure we're out of compliance again
- assertTrue(fsc.removeNotification(sbn_user1_app1)); // was fg, should return true
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
+ entryRemoved(sbn_user1_app1); // was fg, should return true
+ entryRemoved(sbn_user1_app1);
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
// importance upgrade
- fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ entryAdded(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
sbn_user1_app1.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
- fsc.updateNotification(sbn_user1_app1_fg,
+ entryUpdated(sbn_user1_app1_fg,
NotificationManager.IMPORTANCE_DEFAULT); // this is now a fg notification
// finally, let's turn off the service
- fsc.addNotification(makeMockDungeon(USERID_ONE, null),
+ entryAdded(makeMockDisclosure(USERID_ONE, null),
NotificationManager.IMPORTANCE_DEFAULT);
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
}
@Test
@@ -375,8 +276,8 @@
StatusBarNotification sbn_user1_overlay = makeMockSBN(USERID_ONE, "android",
0, "AlertWindowNotification", Notification.FLAG_NO_CLEAR);
- assertTrue(fsc.isSystemAlertNotification(sbn_user1_overlay));
- assertFalse(fsc.isSystemAlertNotification(sbn_user1_app1));
+ assertTrue(mFsc.isSystemAlertNotification(sbn_user1_overlay));
+ assertFalse(mFsc.isSystemAlertNotification(sbn_user1_app1));
}
@Test
@@ -386,54 +287,54 @@
StatusBarNotification sbn_user1_app1 = makeMockFgSBN(USERID_ONE, PKG1, 0, true);
sbn_user1_app1.getNotification().flags = 0;
StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, PKG1, 1, true);
- fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN); // not fg
- assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
- fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // app1 has got it covered
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "otherpkg"));
+ entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN); // not fg
+ assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
+ entryAdded(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // app1 has got it covered
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "otherpkg"));
// let's take out the non-fg notification and see what happens.
- fsc.removeNotification(sbn_user1_app1);
+ entryRemoved(sbn_user1_app1);
// still covered by sbn_user1_app1_fg
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "anyPkg"));
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "anyPkg"));
// let's attempt to downgrade the notification from FLAG_FOREGROUND and see what we get
StatusBarNotification sbn_user1_app1_fg_sneaky = makeMockFgSBN(USERID_ONE, PKG1, 1, true);
sbn_user1_app1_fg_sneaky.getNotification().flags = 0;
- fsc.updateNotification(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_MIN);
- assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "anything"));
+ entryUpdated(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_MIN);
+ assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "anything"));
// ok, ok, we'll put it back
sbn_user1_app1_fg_sneaky.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
- fsc.updateNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "whatever"));
+ entryUpdated(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "whatever"));
- assertTrue(fsc.removeNotification(sbn_user1_app1_fg_sneaky));
- assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "a"));
+ entryRemoved(sbn_user1_app1_fg_sneaky);
+ assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "a"));
// let's try a custom layout
sbn_user1_app1_fg_sneaky = makeMockFgSBN(USERID_ONE, PKG1, 1, false);
- fsc.updateNotification(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_MIN);
- assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "anything"));
+ entryUpdated(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_MIN);
+ assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "anything"));
// now let's test an upgrade (non fg to fg)
- fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN);
- assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "b"));
+ entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN);
+ assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "b"));
sbn_user1_app1.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
- fsc.updateNotification(sbn_user1_app1,
+ entryUpdated(sbn_user1_app1,
NotificationManager.IMPORTANCE_MIN); // this is now a fg notification
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, PKG1));
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, PKG1));
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
// remove it, make sure we're out of compliance again
- assertTrue(fsc.removeNotification(sbn_user1_app1)); // was fg, should return true
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, PKG1));
- assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+ entryRemoved(sbn_user1_app1); // was fg, should return true
+ entryRemoved(sbn_user1_app1);
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, PKG1));
+ assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
}
private StatusBarNotification makeMockSBN(int userid, String pkg, int id, String tag,
@@ -475,7 +376,7 @@
return makeMockSBN(userid, pkg, 1000, "foo", Notification.FLAG_FOREGROUND_SERVICE);
}
- private StatusBarNotification makeMockDungeon(int userid, String[] pkgs) {
+ private StatusBarNotification makeMockDisclosure(int userid, String[] pkgs) {
final Notification n = mock(Notification.class);
n.flags = Notification.FLAG_ONGOING_EVENT;
final Bundle extras = new Bundle();
@@ -488,4 +389,21 @@
sbn.getNotification().extras = extras;
return sbn;
}
+
+ private void entryRemoved(StatusBarNotification notification) {
+ mEntryListener.onEntryRemoved(new NotificationData.Entry(notification),
+ null, null, null, false, false);
+ }
+
+ private void entryAdded(StatusBarNotification notification, int importance) {
+ NotificationData.Entry entry = new NotificationData.Entry(notification);
+ entry.importance = importance;
+ mEntryListener.onPendingEntryAdded(entry);
+ }
+
+ private void entryUpdated(StatusBarNotification notification, int importance) {
+ NotificationData.Entry entry = new NotificationData.Entry(notification);
+ entry.importance = importance;
+ mEntryListener.onEntryUpdated(entry);
+ }
}
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 a2d408e..57c9d29 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
@@ -256,7 +256,6 @@
// Check that no inflation error occurred.
verify(mEntryListener, never()).onInflationError(any(), any());
- verify(mForegroundServiceController).addNotification(eq(mSbn), anyInt());
// Row inflation:
ArgumentCaptor<NotificationData.Entry> entryCaptor = ArgumentCaptor.forClass(
@@ -292,7 +291,6 @@
verify(mEntryListener, never()).onInflationError(any(), any());
verify(mPresenter).updateNotificationViews();
- verify(mForegroundServiceController).updateNotification(eq(mSbn), anyInt());
verify(mEntryListener).onEntryUpdated(mEntry);
assertNotNull(mEntry.getRow());
assertEquals(mEntry.userSentiment,
@@ -310,7 +308,6 @@
verify(mEntryListener, never()).onInflationError(any(), any());
- verify(mForegroundServiceController).removeNotification(mSbn);
verify(mListContainer).cleanUpViewStateForEntry(mEntry);
verify(mPresenter).updateNotificationViews();
verify(mEntryListener).onEntryRemoved(mEntry, mSbn.getKey(), mSbn,