Merge "Do not notify onOpNoted if less than 5s"
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsController.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsController.java
index 4966fc6..2661d89 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsController.java
@@ -27,7 +27,9 @@
public interface AppOpsController {
/**
- * Callback to notify when the state of active AppOps tracked by the controller has changed
+ * Callback to notify when the state of active AppOps tracked by the controller has changed.
+ * AppOps that are noted will not be notified every time, just when the tracked state changes
+ * between currently in use and not.
*/
interface Callback {
void onActiveStateChanged(int code, int uid, String packageName, boolean active);
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 139bfd5..bad6b54 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -52,6 +52,9 @@
AppOpsManager.OnOpActiveChangedInternalListener,
AppOpsManager.OnOpNotedListener, Dumpable {
+ // This is the minimum time that we will keep AppOps that are noted on record. If multiple
+ // occurrences of the same (op, package, uid) happen in a shorter interval, they will not be
+ // notified to listeners.
private static final long NOTED_OP_TIME_DELAY_MS = 5000;
private static final String TAG = "AppOpsControllerImpl";
private static final boolean DEBUG = false;
@@ -167,7 +170,8 @@
if (mCallbacks.isEmpty()) setListening(false);
}
- private AppOpItem getAppOpItem(List<AppOpItem> appOpList, int code, int uid,
+ // Find item number in list, only call if the list passed is locked
+ private AppOpItem getAppOpItemLocked(List<AppOpItem> appOpList, int code, int uid,
String packageName) {
final int itemsQ = appOpList.size();
for (int i = 0; i < itemsQ; i++) {
@@ -182,7 +186,7 @@
private boolean updateActives(int code, int uid, String packageName, boolean active) {
synchronized (mActiveItems) {
- AppOpItem item = getAppOpItem(mActiveItems, code, uid, packageName);
+ AppOpItem item = getAppOpItemLocked(mActiveItems, code, uid, packageName);
if (item == null && active) {
item = new AppOpItem(code, uid, packageName, System.currentTimeMillis());
mActiveItems.add(item);
@@ -200,7 +204,7 @@
private void removeNoted(int code, int uid, String packageName) {
AppOpItem item;
synchronized (mNotedItems) {
- item = getAppOpItem(mNotedItems, code, uid, packageName);
+ item = getAppOpItemLocked(mNotedItems, code, uid, packageName);
if (item == null) return;
mNotedItems.remove(item);
if (DEBUG) Log.w(TAG, "Removed item: " + item.toString());
@@ -208,17 +212,20 @@
notifySuscribers(code, uid, packageName, false);
}
- private void addNoted(int code, int uid, String packageName) {
+ private boolean addNoted(int code, int uid, String packageName) {
AppOpItem item;
+ boolean createdNew = false;
synchronized (mNotedItems) {
- item = getAppOpItem(mNotedItems, code, uid, packageName);
+ item = getAppOpItemLocked(mNotedItems, code, uid, packageName);
if (item == null) {
item = new AppOpItem(code, uid, packageName, System.currentTimeMillis());
mNotedItems.add(item);
if (DEBUG) Log.w(TAG, "Added item: " + item.toString());
+ createdNew = true;
}
}
mBGHandler.scheduleRemoval(item, NOTED_OP_TIME_DELAY_MS);
+ return createdNew;
}
/**
@@ -329,13 +336,15 @@
Log.w(TAG, "Op: " + code + " with result " + AppOpsManager.MODE_NAMES[result]);
}
if (result != AppOpsManager.MODE_ALLOWED) return;
- addNoted(code, uid, packageName);
- mBGHandler.post(() -> notifySuscribers(code, uid, packageName, true));
+ if (addNoted(code, uid, packageName)) {
+ mBGHandler.post(() -> notifySuscribers(code, uid, packageName, true));
+ }
}
private void notifySuscribers(int code, int uid, String packageName, boolean active) {
if (mCallbacksByCode.containsKey(code)
&& isUserVisible(code, uid, packageName)) {
+ if (DEBUG) Log.d(TAG, "Notifying of change in package " + packageName);
for (Callback cb: mCallbacksByCode.get(code)) {
cb.onActiveStateChanged(code, uid, packageName, active);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
index 26185e1..af0ef82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -48,6 +48,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -220,4 +222,33 @@
verify(mMockHandler).removeCallbacksAndMessages(null);
assertTrue(mController.getActiveAppOps().isEmpty());
}
+
+ @Test
+ public void noDoubleUpdateOnOpNoted() {
+ mController.setBGHandler(mMockHandler);
+
+ mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
+ AppOpsManager.MODE_ALLOWED);
+ mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
+ AppOpsManager.MODE_ALLOWED);
+
+ // Only one post to notify subscribers
+ verify(mMockHandler, times(1)).post(any());
+
+ List<AppOpItem> list = mController.getActiveAppOps();
+ assertEquals(1, list.size());
+ }
+
+ @Test
+ public void onDoubleOPNoted_scheduleTwiceForRemoval() {
+ mController.setBGHandler(mMockHandler);
+
+ mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
+ AppOpsManager.MODE_ALLOWED);
+ mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
+ AppOpsManager.MODE_ALLOWED);
+
+ // Only one post to notify subscribers
+ verify(mMockHandler, times(2)).scheduleRemoval(any(), anyLong());
+ }
}