summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Tony Huang <tonyychuang@google.com> 2023-09-05 06:15:02 +0000
committer Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> 2023-09-05 06:15:02 +0000
commit2fd6dc217581f8a9121a20a2f6b83026edecf0c7 (patch)
tree7d865c576e9deedfe99c94426453cd04b97a7308
parent136b05654365bf872f03857742a6edabe641d209 (diff)
parent68ef56859f8d8c83ec18f323bb2ff5e003892973 (diff)
VRR: Allowlist for small area detection am: 68ef56859f
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/24476723 Change-Id: I86fda513ded0bea124c74e09c93962157132ee3a Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--core/res/res/values/config.xml7
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java7
-rw-r--r--services/core/java/com/android/server/display/SmallAreaDetectionController.java177
-rw-r--r--services/core/jni/Android.bp1
-rw-r--r--services/core/jni/com_android_server_display_SmallAreaDetectionController.cpp67
-rw-r--r--services/core/jni/onload.cpp2
-rw-r--r--services/tests/displayservicetests/Android.bp1
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java11
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/SmallAreaDetectionControllerTest.java138
10 files changed, 411 insertions, 2 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index fe6b897f3fc0..101857057514 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5380,6 +5380,13 @@
of known compatibility issues. -->
<string-array name="config_highRefreshRateBlacklist"></string-array>
+ <!-- The list of packages to automatically opt in to refresh rate suppressing by small area
+ detection. Format of this array should be packageName:threshold and threshold value should
+ be between 0 to 1-->
+ <string-array name="config_smallAreaDetectionAllowlist" translatable="false">
+ <!-- Add packages:threshold here -->
+ </string-array>
+
<!-- The list of packages to force slowJpegMode for Apps using Camera API1 -->
<string-array name="config_forceSlowJpegModeList" translatable="false">
<!-- Add packages here -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e3b873b4d3bd..852dc8cceb40 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4240,6 +4240,8 @@
<java-symbol type="array" name="config_highRefreshRateBlacklist" />
<java-symbol type="array" name="config_forceSlowJpegModeList" />
+ <java-symbol type="array" name="config_smallAreaDetectionAllowlist" />
+
<java-symbol type="layout" name="chooser_dialog" />
<java-symbol type="layout" name="chooser_dialog_item" />
<java-symbol type="drawable" name="chooser_dialog_background" />
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 898a3c416083..6546f6e533c0 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -468,6 +468,8 @@ public final class DisplayManagerService extends SystemService {
private SensorManager mSensorManager;
private BrightnessTracker mBrightnessTracker;
+ private SmallAreaDetectionController mSmallAreaDetectionController;
+
// Whether minimal post processing is allowed by the user.
@GuardedBy("mSyncRoot")
@@ -731,6 +733,8 @@ public final class DisplayManagerService extends SystemService {
filter.addAction(Intent.ACTION_DOCK_EVENT);
mContext.registerReceiver(mIdleModeReceiver, filter);
+
+ mSmallAreaDetectionController = SmallAreaDetectionController.create(mContext);
}
@VisibleForTesting
@@ -3046,6 +3050,9 @@ public final class DisplayManagerService extends SystemService {
pw.println();
mDisplayModeDirector.dump(pw);
mBrightnessSynchronizer.dump(pw);
+ if (mSmallAreaDetectionController != null) {
+ mSmallAreaDetectionController.dump(pw);
+ }
}
private static float[] getFloatArray(TypedArray array) {
diff --git a/services/core/java/com/android/server/display/SmallAreaDetectionController.java b/services/core/java/com/android/server/display/SmallAreaDetectionController.java
new file mode 100644
index 000000000000..adaa5390cb9b
--- /dev/null
+++ b/services/core/java/com/android/server/display/SmallAreaDetectionController.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2023 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.server.display;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageManagerInternal;
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfigInterface;
+import android.util.ArrayMap;
+import android.util.SparseArray;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
+import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Map;
+
+final class SmallAreaDetectionController {
+ private static native void nativeUpdateSmallAreaDetection(int[] uids, float[] thresholds);
+ private static native void nativeSetSmallAreaDetectionThreshold(int uid, float threshold);
+
+ // TODO(b/281720315): Move this to DeviceConfig once server side ready.
+ private static final String KEY_SMALL_AREA_DETECTION_ALLOWLIST =
+ "small_area_detection_allowlist";
+
+ private final Object mLock = new Object();
+ private final Context mContext;
+ private final PackageManagerInternal mPackageManager;
+ private final UserManagerInternal mUserManager;
+ @GuardedBy("mLock")
+ private final Map<String, Float> mAllowPkgMap = new ArrayMap<>();
+ // TODO(b/298722189): Update allowlist when user changes
+ @GuardedBy("mLock")
+ private int[] mUserIds;
+
+ static SmallAreaDetectionController create(@NonNull Context context) {
+ final SmallAreaDetectionController controller =
+ new SmallAreaDetectionController(context, DeviceConfigInterface.REAL);
+ final String property = DeviceConfigInterface.REAL.getProperty(
+ DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_SMALL_AREA_DETECTION_ALLOWLIST);
+ controller.updateAllowlist(property);
+ return controller;
+ }
+
+ @VisibleForTesting
+ SmallAreaDetectionController(Context context, DeviceConfigInterface deviceConfig) {
+ mContext = context;
+ mPackageManager = LocalServices.getService(PackageManagerInternal.class);
+ mUserManager = LocalServices.getService(UserManagerInternal.class);
+ deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ BackgroundThread.getExecutor(),
+ new SmallAreaDetectionController.OnPropertiesChangedListener());
+ mPackageManager.getPackageList(new PackageReceiver());
+ }
+
+ @VisibleForTesting
+ void updateAllowlist(@Nullable String property) {
+ synchronized (mLock) {
+ mAllowPkgMap.clear();
+ if (property != null) {
+ final String[] mapStrings = property.split(",");
+ for (String mapString : mapStrings) putToAllowlist(mapString);
+ } else {
+ final String[] defaultMapStrings = mContext.getResources()
+ .getStringArray(R.array.config_smallAreaDetectionAllowlist);
+ for (String defaultMapString : defaultMapStrings) putToAllowlist(defaultMapString);
+ }
+ updateSmallAreaDetection();
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void putToAllowlist(String rowData) {
+ // Data format: package:threshold - e.g. "com.abc.music:0.05"
+ final String[] items = rowData.split(":");
+ if (items.length == 2) {
+ try {
+ final String pkg = items[0];
+ final float threshold = Float.valueOf(items[1]);
+ mAllowPkgMap.put(pkg, threshold);
+ } catch (Exception e) {
+ // Just skip if items[1] - the threshold is not parsable number
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void updateUidListForAllUsers(SparseArray<Float> list, String pkg, float threshold) {
+ for (int i = 0; i < mUserIds.length; i++) {
+ final int userId = mUserIds[i];
+ final int uid = mPackageManager.getPackageUid(pkg, 0, userId);
+ if (uid > 0) list.put(uid, threshold);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void updateSmallAreaDetection() {
+ if (mAllowPkgMap.isEmpty()) return;
+
+ mUserIds = mUserManager.getUserIds();
+
+ final SparseArray<Float> uidThresholdList = new SparseArray<>();
+ for (String pkg : mAllowPkgMap.keySet()) {
+ final float threshold = mAllowPkgMap.get(pkg);
+ updateUidListForAllUsers(uidThresholdList, pkg, threshold);
+ }
+
+ final int[] uids = new int[uidThresholdList.size()];
+ final float[] thresholds = new float[uidThresholdList.size()];
+ for (int i = 0; i < uidThresholdList.size(); i++) {
+ uids[i] = uidThresholdList.keyAt(i);
+ thresholds[i] = uidThresholdList.valueAt(i);
+ }
+ updateSmallAreaDetection(uids, thresholds);
+ }
+
+ @VisibleForTesting
+ void updateSmallAreaDetection(int[] uids, float[] thresholds) {
+ nativeUpdateSmallAreaDetection(uids, thresholds);
+ }
+
+ void setSmallAreaDetectionThreshold(int uid, float threshold) {
+ nativeSetSmallAreaDetectionThreshold(uid, threshold);
+ }
+
+ void dump(PrintWriter pw) {
+ pw.println("Small area detection allowlist");
+ pw.println(" Packages:");
+ synchronized (mLock) {
+ for (String pkg : mAllowPkgMap.keySet()) {
+ pw.println(" " + pkg + " threshold = " + mAllowPkgMap.get(pkg));
+ }
+ pw.println(" mUserIds=" + Arrays.toString(mUserIds));
+ }
+ }
+
+ private class OnPropertiesChangedListener implements DeviceConfig.OnPropertiesChangedListener {
+ public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
+ if (properties.getKeyset().contains(KEY_SMALL_AREA_DETECTION_ALLOWLIST)) {
+ updateAllowlist(
+ properties.getString(KEY_SMALL_AREA_DETECTION_ALLOWLIST, null /*default*/));
+ }
+ }
+ }
+
+ private final class PackageReceiver implements PackageManagerInternal.PackageListObserver {
+ @Override
+ public void onPackageAdded(@NonNull String packageName, int uid) {
+ synchronized (mLock) {
+ if (mAllowPkgMap.containsKey(packageName)) {
+ setSmallAreaDetectionThreshold(uid, mAllowPkgMap.get(packageName));
+ }
+ }
+ }
+ }
+}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 6f2455e073a7..a0a7adb910fd 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -41,6 +41,7 @@ cc_library_static {
"com_android_server_companion_virtual_InputController.cpp",
"com_android_server_devicepolicy_CryptoTestHelper.cpp",
"com_android_server_display_DisplayControl.cpp",
+ "com_android_server_display_SmallAreaDetectionController.cpp",
"com_android_server_connectivity_Vpn.cpp",
"com_android_server_gpu_GpuService.cpp",
"com_android_server_HardwarePropertiesManagerService.cpp",
diff --git a/services/core/jni/com_android_server_display_SmallAreaDetectionController.cpp b/services/core/jni/com_android_server_display_SmallAreaDetectionController.cpp
new file mode 100644
index 000000000000..b256f168f2af
--- /dev/null
+++ b/services/core/jni/com_android_server_display_SmallAreaDetectionController.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#define LOG_TAG "SmallAreaDetectionController"
+
+#include <gui/SurfaceComposerClient.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+
+#include "jni.h"
+#include "utils/Log.h"
+
+namespace android {
+static void nativeUpdateSmallAreaDetection(JNIEnv* env, jclass clazz, jintArray juids,
+ jfloatArray jthresholds) {
+ if (juids == nullptr || jthresholds == nullptr) return;
+
+ ScopedIntArrayRO uids(env, juids);
+ ScopedFloatArrayRO thresholds(env, jthresholds);
+
+ if (uids.size() != thresholds.size()) {
+ ALOGE("uids size exceeds thresholds size!");
+ return;
+ }
+
+ std::vector<int32_t> uidVector;
+ std::vector<float> thresholdVector;
+ size_t size = uids.size();
+ uidVector.reserve(size);
+ thresholdVector.reserve(size);
+ for (int i = 0; i < size; i++) {
+ uidVector.push_back(static_cast<int32_t>(uids[i]));
+ thresholdVector.push_back(static_cast<float>(thresholds[i]));
+ }
+ SurfaceComposerClient::updateSmallAreaDetection(uidVector, thresholdVector);
+}
+
+static void nativeSetSmallAreaDetectionThreshold(JNIEnv* env, jclass clazz, jint uid,
+ jfloat threshold) {
+ SurfaceComposerClient::setSmallAreaDetectionThreshold(uid, threshold);
+}
+
+static const JNINativeMethod gMethods[] = {
+ {"nativeUpdateSmallAreaDetection", "([I[F)V", (void*)nativeUpdateSmallAreaDetection},
+ {"nativeSetSmallAreaDetectionThreshold", "(IF)V",
+ (void*)nativeSetSmallAreaDetectionThreshold},
+};
+
+int register_android_server_display_smallAreaDetectionController(JNIEnv* env) {
+ return jniRegisterNativeMethods(env, "com/android/server/display/SmallAreaDetectionController",
+ gMethods, NELEM(gMethods));
+}
+
+}; // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 290ad8de9547..63c3b4d1834c 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -66,6 +66,7 @@ int register_android_server_app_GameManagerService(JNIEnv* env);
int register_com_android_server_wm_TaskFpsCallbackController(JNIEnv* env);
int register_com_android_server_display_DisplayControl(JNIEnv* env);
int register_com_android_server_SystemClockTime(JNIEnv* env);
+int register_android_server_display_smallAreaDetectionController(JNIEnv* env);
};
using namespace android;
@@ -124,5 +125,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_com_android_server_wm_TaskFpsCallbackController(env);
register_com_android_server_display_DisplayControl(env);
register_com_android_server_SystemClockTime(env);
+ register_android_server_display_smallAreaDetectionController(env);
return JNI_VERSION_1_4;
}
diff --git a/services/tests/displayservicetests/Android.bp b/services/tests/displayservicetests/Android.bp
index 4f555d9cc953..2397850dc745 100644
--- a/services/tests/displayservicetests/Android.bp
+++ b/services/tests/displayservicetests/Android.bp
@@ -34,6 +34,7 @@ android_test {
"mockingservicestests-utils-mockito",
"platform-compat-test-rules",
"platform-test-annotations",
+ "service-permission.stubs.system_server",
"services.core",
"servicestests-utils",
"testables",
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index 50cf1696ba83..14586aef2c44 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -58,6 +58,7 @@ import android.compat.testing.PlatformCompatChangeRule;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -106,6 +107,7 @@ import com.android.server.display.DisplayManagerService.DeviceStateListener;
import com.android.server.display.DisplayManagerService.SyncRoot;
import com.android.server.input.InputManagerInternal;
import com.android.server.lights.LightsManager;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.sensors.SensorManagerInternal;
import com.android.server.wm.WindowManagerInternal;
@@ -254,10 +256,11 @@ public class DisplayManagerServiceTest {
@Mock LocalDisplayAdapter.SurfaceControlProxy mSurfaceControlProxy;
@Mock IBinder mMockDisplayToken;
@Mock SensorManagerInternal mMockSensorManagerInternal;
-
@Mock SensorManager mSensorManager;
-
@Mock DisplayDeviceConfig mMockDisplayDeviceConfig;
+ @Mock PackageManagerInternal mMockPackageManagerInternal;
+ @Mock UserManagerInternal mMockUserManagerInternal;
+
@Captor ArgumentCaptor<ContentRecordingSession> mContentRecordingSessionCaptor;
@@ -276,6 +279,10 @@ public class DisplayManagerServiceTest {
LocalServices.removeServiceForTest(VirtualDeviceManagerInternal.class);
LocalServices.addService(
VirtualDeviceManagerInternal.class, mMockVirtualDeviceManagerInternal);
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
+ LocalServices.addService(PackageManagerInternal.class, mMockPackageManagerInternal);
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
+ LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal);
// TODO: b/287945043
mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/SmallAreaDetectionControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/SmallAreaDetectionControllerTest.java
new file mode 100644
index 000000000000..1ce79a5b596b
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/display/SmallAreaDetectionControllerTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2023 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.server.display;
+
+import static android.os.Process.INVALID_UID;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ContextWrapper;
+import android.content.pm.PackageManagerInternal;
+import android.provider.DeviceConfigInterface;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SmallAreaDetectionControllerTest {
+
+ @Rule
+ public MockitoRule mRule = MockitoJUnit.rule();
+
+ @Mock
+ private PackageManagerInternal mMockPackageManagerInternal;
+ @Mock
+ private UserManagerInternal mMockUserManagerInternal;
+
+ private SmallAreaDetectionController mSmallAreaDetectionController;
+
+ private static final String PKG_A = "com.a.b.c";
+ private static final String PKG_B = "com.d.e.f";
+ private static final String PKG_NOT_INSTALLED = "com.not.installed";
+ private static final float THRESHOLD_A = 0.05f;
+ private static final float THRESHOLD_B = 0.07f;
+ private static final int USER_1 = 110;
+ private static final int USER_2 = 111;
+ private static final int UID_A_1 = 11011111;
+ private static final int UID_A_2 = 11111111;
+ private static final int UID_B_1 = 11022222;
+ private static final int UID_B_2 = 11122222;
+
+ @Before
+ public void setup() {
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
+ LocalServices.addService(PackageManagerInternal.class, mMockPackageManagerInternal);
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
+ LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal);
+
+ when(mMockUserManagerInternal.getUserIds()).thenReturn(new int[]{USER_1, USER_2});
+ when(mMockPackageManagerInternal.getPackageUid(PKG_A, 0, USER_1)).thenReturn(UID_A_1);
+ when(mMockPackageManagerInternal.getPackageUid(PKG_A, 0, USER_2)).thenReturn(UID_A_2);
+ when(mMockPackageManagerInternal.getPackageUid(PKG_B, 0, USER_1)).thenReturn(UID_B_1);
+ when(mMockPackageManagerInternal.getPackageUid(PKG_B, 0, USER_2)).thenReturn(UID_B_2);
+ when(mMockPackageManagerInternal.getPackageUid(PKG_NOT_INSTALLED, 0, USER_1)).thenReturn(
+ INVALID_UID);
+ when(mMockPackageManagerInternal.getPackageUid(PKG_NOT_INSTALLED, 0, USER_2)).thenReturn(
+ INVALID_UID);
+
+ mSmallAreaDetectionController = spy(new SmallAreaDetectionController(
+ new ContextWrapper(ApplicationProvider.getApplicationContext()),
+ DeviceConfigInterface.REAL));
+ doNothing().when(mSmallAreaDetectionController).updateSmallAreaDetection(any(), any());
+ }
+
+ @Test
+ public void testUpdateAllowlist_validProperty() {
+ final String property = PKG_A + ":" + THRESHOLD_A + "," + PKG_B + ":" + THRESHOLD_B;
+ mSmallAreaDetectionController.updateAllowlist(property);
+
+ final int[] resultUidArray = {UID_A_1, UID_B_1, UID_A_2, UID_B_2};
+ final float[] resultThresholdArray = {THRESHOLD_A, THRESHOLD_B, THRESHOLD_A, THRESHOLD_B};
+ verify(mSmallAreaDetectionController).updateSmallAreaDetection(eq(resultUidArray),
+ eq(resultThresholdArray));
+ }
+
+ @Test
+ public void testUpdateAllowlist_includeInvalidRow() {
+ final String property = PKG_A + "," + PKG_B + ":" + THRESHOLD_B;
+ mSmallAreaDetectionController.updateAllowlist(property);
+
+ final int[] resultUidArray = {UID_B_1, UID_B_2};
+ final float[] resultThresholdArray = {THRESHOLD_B, THRESHOLD_B};
+ verify(mSmallAreaDetectionController).updateSmallAreaDetection(eq(resultUidArray),
+ eq(resultThresholdArray));
+ }
+
+ @Test
+ public void testUpdateAllowlist_includeNotInstalledPkg() {
+ final String property =
+ PKG_A + ":" + THRESHOLD_A + "," + PKG_NOT_INSTALLED + ":" + THRESHOLD_B;
+ mSmallAreaDetectionController.updateAllowlist(property);
+
+ final int[] resultUidArray = {UID_A_1, UID_A_2};
+ final float[] resultThresholdArray = {THRESHOLD_A, THRESHOLD_A};
+ verify(mSmallAreaDetectionController).updateSmallAreaDetection(eq(resultUidArray),
+ eq(resultThresholdArray));
+ }
+
+ @Test
+ public void testUpdateAllowlist_invalidProperty() {
+ final String property = PKG_A;
+ mSmallAreaDetectionController.updateAllowlist(property);
+
+ verify(mSmallAreaDetectionController, never()).updateSmallAreaDetection(any(), any());
+ }
+}