summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/DependencyBinder.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java315
-rw-r--r--packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java309
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java2
4 files changed, 287 insertions, 345 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
index 1ee1dcf74555..f324a05bafff 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
@@ -219,12 +219,6 @@ public abstract class DependencyBinder {
/**
*/
@Binds
- public abstract ForegroundServiceController provideForegroundService(
- ForegroundServiceControllerImpl controllerImpl);
-
- /**
- */
- @Binds
public abstract PowerUI.WarningsUI provideWarningsUi(PowerNotificationWarnings controllerImpl);
/**
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
index ae6ee2af29fd..5c2483881713 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
@@ -15,65 +15,322 @@
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.
+ */
+@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 Object mMutex = new Object();
+
+ @Inject
+ public ForegroundServiceController(Context context) {
+ mContext = context;
+ }
-public interface ForegroundServiceController {
/**
- * @param sbn notification that was just posted
- * @param importance
+ * @return true if this user has services missing notifications and therefore needs a
+ * disclosure notification.
*/
- void addNotification(StatusBarNotification sbn, int importance);
+ public boolean isDungeonNeededForUser(int userId) {
+ synchronized (mMutex) {
+ final UserServices services = mUserServices.get(userId);
+ if (services == null) return false;
+ return services.isDungeonNeeded();
+ }
+ }
/**
- * @param sbn notification that was just changed in some way
- * @param newImportance
+ * @return true if this user/pkg has a missing or custom layout notification and therefore needs
+ * a disclosure notification for system alert windows.
*/
- void updateNotification(StatusBarNotification sbn, int newImportance);
+ public boolean isSystemAlertWarningNeeded(int userId, String pkg) {
+ synchronized (mMutex) {
+ final UserServices services = mUserServices.get(userId);
+ if (services == null) return false;
+ return services.getStandardLayoutKey(pkg) == null;
+ }
+ }
/**
- * @param sbn notification that was just canceled
+ * Returns the key of the foreground service from this package using the standard template,
+ * if one exists.
*/
- boolean removeNotification(StatusBarNotification sbn);
+ @Nullable
+ public String getStandardLayoutKey(int userId, String pkg) {
+ synchronized (mMutex) {
+ final UserServices services = mUserServices.get(userId);
+ if (services == null) return null;
+ return services.getStandardLayoutKey(pkg);
+ }
+ }
/**
- * @param userId
- * @return true if this user has services missing notifications and therefore needs a
- * disclosure notification.
+ * Gets active app ops for this user and package
*/
- boolean isDungeonNeededForUser(int userId);
+ @Nullable
+ public ArraySet<Integer> getAppOps(int userId, String pkg) {
+ synchronized (mMutex) {
+ final UserServices services = mUserServices.get(userId);
+ if (services == null) {
+ return null;
+ }
+ return services.getFeatures(pkg);
+ }
+ }
/**
- * @param sbn
- * @return true if sbn is the system-provided "dungeon" (list of running foreground services).
+ * 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.
*/
- boolean isDungeonNotification(StatusBarNotification sbn);
+ public void onAppOpChanged(int code, int uid, String packageName, boolean active) {
+ int userId = UserHandle.getUserId(uid);
+ synchronized (mMutex) {
+ UserServices userServices = mUserServices.get(userId);
+ if (userServices == null) {
+ userServices = new UserServices();
+ mUserServices.put(userId, userServices);
+ }
+ if (active) {
+ userServices.addOp(packageName, code);
+ } else {
+ userServices.removeOp(packageName, code);
+ }
+ }
+ }
/**
- * @return true if sbn is one of the window manager "drawing over other apps" notifications
+ * @param sbn notification that was just posted
+ * @param importance
*/
- boolean isSystemAlertNotification(StatusBarNotification sbn);
+ public void addNotification(StatusBarNotification sbn, int importance) {
+ updateNotification(sbn, importance);
+ }
/**
- * Returns the key of the foreground service from this package using the standard template,
- * if one exists.
+ * @param sbn notification that was just removed
*/
- @Nullable String getStandardLayoutKey(int userId, String pkg);
+ public boolean removeNotification(StatusBarNotification sbn) {
+ 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));
+ }
+ 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 true if this user/pkg has a missing or custom layout notification and therefore needs
- * a disclosure notification for system alert windows.
+ * @param sbn notification that was just changed in some way
*/
- boolean isSystemAlertWarningNeeded(int userId, String pkg);
+ 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());
+ }
+ }
+ }
+ }
+ }
/**
- * 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.
+ * @return true if sbn is the system-provided "dungeon" (list of running foreground services).
*/
- void onAppOpChanged(int code, int uid, String packageName, boolean active);
+ public boolean isDungeonNotification(StatusBarNotification sbn) {
+ return sbn.getId() == SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES
+ && sbn.getTag() == null
+ && sbn.getPackageName().equals("android");
+ }
/**
- * Gets active app ops for this user and package
+ * @return true if sbn is one of the window manager "drawing over other apps" notifications
*/
- @Nullable ArraySet<Integer> getAppOps(int userId, String packageName);
+ public boolean isSystemAlertNotification(StatusBarNotification sbn) {
+ return sbn.getPackageName().equals("android")
+ && sbn.getTag() != null
+ && sbn.getTag().contains("AlertWindowNotification");
+ }
+
+ /**
+ * Struct to track relevant packages and notifications for a userid's foreground services.
+ */
+ 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);
+
+ // 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
+ + '}';
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java
deleted file mode 100644
index ae446ddc91ab..000000000000
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright (C) 2017 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.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.
- */
-@Singleton
-public class ForegroundServiceControllerImpl
- implements ForegroundServiceController {
-
- // shelf life of foreground services before they go bad
- public 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 Object mMutex = new Object();
-
- @Inject
- public ForegroundServiceControllerImpl(Context context) {
- mContext = context;
- }
-
- @Override
- public boolean isDungeonNeededForUser(int userId) {
- synchronized (mMutex) {
- final UserServices services = mUserServices.get(userId);
- if (services == null) return false;
- return services.isDungeonNeeded();
- }
- }
-
- @Override
- public boolean isSystemAlertWarningNeeded(int userId, String pkg) {
- synchronized (mMutex) {
- final UserServices services = mUserServices.get(userId);
- if (services == null) return false;
- return services.getStandardLayoutKey(pkg) == null;
- }
- }
-
- @Override
- public String getStandardLayoutKey(int userId, String pkg) {
- synchronized (mMutex) {
- final UserServices services = mUserServices.get(userId);
- if (services == null) return null;
- return services.getStandardLayoutKey(pkg);
- }
- }
-
- @Override
- public ArraySet<Integer> getAppOps(int userId, String pkg) {
- synchronized (mMutex) {
- final UserServices services = mUserServices.get(userId);
- if (services == null) {
- return null;
- }
- return services.getFeatures(pkg);
- }
- }
-
- @Override
- public void onAppOpChanged(int code, int uid, String packageName, boolean active) {
- int userId = UserHandle.getUserId(uid);
- synchronized (mMutex) {
- UserServices userServices = mUserServices.get(userId);
- if (userServices == null) {
- userServices = new UserServices();
- mUserServices.put(userId, userServices);
- }
- if (active) {
- userServices.addOp(packageName, code);
- } else {
- userServices.removeOp(packageName, code);
- }
- }
- }
-
- @Override
- public void addNotification(StatusBarNotification sbn, int importance) {
- updateNotification(sbn, importance);
- }
-
- @Override
- public boolean removeNotification(StatusBarNotification sbn) {
- 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));
- }
- 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());
- }
- }
- }
-
- @Override
- 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());
- }
- }
- }
- }
- }
-
- @Override
- public boolean isDungeonNotification(StatusBarNotification sbn) {
- return sbn.getId() == SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES
- && sbn.getTag() == null
- && sbn.getPackageName().equals("android");
- }
-
- @Override
- public boolean isSystemAlertNotification(StatusBarNotification sbn) {
- return sbn.getPackageName().equals("android")
- && sbn.getTag() != null
- && sbn.getTag().contains("AlertWindowNotification");
- }
-
- /**
- * Struct to track relevant packages and notifications for a userid's foreground services.
- */
- 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);
-
- // 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 +
- '}';
- }
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index f278a17d0637..d8b473b4e16c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -50,7 +50,7 @@ public class ForegroundServiceControllerTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
- fsc = new ForegroundServiceControllerImpl(mContext);
+ fsc = new ForegroundServiceController(mContext);
}
@Test