diff options
19 files changed, 459 insertions, 18 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 9a417e9da3dd..2ab8d80b4e51 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -21,6 +21,7 @@ java_defaults { ":android.os.flags-aconfig-java{.generated_srcjars}", ":android.os.vibrator.flags-aconfig-java{.generated_srcjars}", ":android.security.flags-aconfig-java{.generated_srcjars}", + ":android.media.flags-aconfig-java{.generated_srcjars}", ":camera_platform_flags_core_java_lib{.generated_srcjars}", ":com.android.window.flags.window-aconfig-java{.generated_srcjars}", ":com.android.text.flags-aconfig-java{.generated_srcjars}", @@ -157,3 +158,16 @@ java_aconfig_library { aconfig_declarations: "android.os.vibrator.flags-aconfig", defaults: ["framework-minus-apex-aconfig-java-defaults"], } + +// Media +aconfig_declarations { + name: "android.media.flags-aconfig", + package: "android.media", + srcs: ["media/java/android/media/*.aconfig"], +} + +java_aconfig_library { + name: "android.media.flags-aconfig-java", + aconfig_declarations: "android.media.flags-aconfig", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig index 560e41b1aa33..b8d251fc5cc5 100644 --- a/core/java/android/window/flags/windowing_sdk.aconfig +++ b/core/java/android/window/flags/windowing_sdk.aconfig @@ -8,3 +8,10 @@ flag { description: "Whether the feature to sync different window-related config updates is enabled" bug: "260873529" } + +flag { + namespace: "windowing_sdk" + name: "activity_embedding_overlay_presentation_flag" + description: "Whether the overlay presentation feature is enabled" + bug: "243518738" +} diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 03480e42e5ac..302c7fad8173 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -5480,6 +5480,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 7ea597420746..02209a7ff86b 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4288,6 +4288,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/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java index a41fb64716e2..0778311e98bd 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java @@ -67,7 +67,6 @@ import android.view.View; import android.window.WindowContextInfo; import android.window.WindowTokenClientController; -import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.rule.ActivityTestRule; @@ -254,15 +253,9 @@ public class ActivityThreadTest { // Execute a local relaunch item with current scaled config (e.g. simulate recreate), // the config should not be scaled again. - final Configuration currentConfig = activity.getResources().getConfiguration(); - final ClientTransaction localTransaction = - newTransaction(activityThread, activity.getActivityToken()); - localTransaction.addCallback(ActivityRelaunchItem.obtain( - null /* pendingResults */, null /* pendingIntents */, 0 /* configChanges */, - new MergedConfiguration(currentConfig, currentConfig), - true /* preserveWindow */)); InstrumentationRegistry.getInstrumentation().runOnMainSync( - () -> activityThread.executeTransaction(localTransaction)); + () -> activityThread.executeTransaction( + newRelaunchResumeTransaction(activity))); assertScreenScale(scale, activity, originalActivityConfig, originalActivityMetrics); } finally { @@ -630,7 +623,6 @@ public class ActivityThreadTest { }); } - @FlakyTest(bugId = 298331121) @Test public void testHandleConfigurationChanged_DoesntOverrideActivityConfig() { final TestActivity activity = mActivityTestRule.launchActivity(new Intent()); diff --git a/media/java/android/media/flags.aconfig b/media/java/android/media/flags.aconfig new file mode 100644 index 000000000000..8567a3b166ab --- /dev/null +++ b/media/java/android/media/flags.aconfig @@ -0,0 +1,8 @@ +package: "android.media" + +flag { + name: "haptics_customization_enabled" + namespace: "media" + description: "Enables the haptics customization feature" + bug: "241918098" +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt index 90a723f707da..b77368a429ae 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt @@ -253,6 +253,7 @@ private fun SingleRowTopAppBar( hideTitleSemantics = false, navigationIcon = navigationIcon, actions = actionsRow, + titleScaleDisabled = false, ) } } @@ -426,6 +427,7 @@ private fun TwoRowsTopAppBar( * accessibility services at the same time, when animating between collapsed / expanded states. * @param navigationIcon a navigation icon [Composable] * @param actions actions [Composable] + * @param titleScaleDisabled whether the title font scaling is disabled. Default is disabled. */ @Composable private fun TopAppBarLayout( @@ -443,6 +445,7 @@ private fun TopAppBarLayout( hideTitleSemantics: Boolean, navigationIcon: @Composable () -> Unit, actions: @Composable () -> Unit, + titleScaleDisabled: Boolean = true, ) { Layout( { @@ -466,9 +469,12 @@ private fun TopAppBarLayout( ProvideTextStyle(value = titleTextStyle) { CompositionLocalProvider( LocalContentColor provides titleContentColor, - // Disable the title font scaling by only passing the density but not the - // font scale. - LocalDensity provides Density(density = LocalDensity.current.density), + LocalDensity provides with(LocalDensity.current) { + Density( + density = density, + fontScale = if (titleScaleDisabled) 1f else fontScale, + ) + }, content = title ) } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt index d437e3579354..696e8776ccd7 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt @@ -18,6 +18,7 @@ package com.android.settingslib.spa.widget.scaffold import androidx.activity.compose.BackHandler import androidx.appcompat.R +import androidx.compose.foundation.focusable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.RowScope @@ -96,7 +97,8 @@ fun SearchScaffold( Modifier .padding(paddingValues.horizontalValues()) .padding(top = paddingValues.calculateTopPadding()) - .fillMaxSize(), + .focusable() + .fillMaxSize() ) { content( paddingValues.calculateBottomPadding(), diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt index f68078a8a340..82b032450938 100644 --- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt @@ -29,6 +29,7 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.util.Compile import com.android.systemui.util.traceSection import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher @@ -239,7 +240,7 @@ constructor( private companion object { const val TAG = "DisplayRepository" - val DEBUG = Log.isLoggable(TAG, Log.DEBUG) + val DEBUG = Log.isLoggable(TAG, Log.DEBUG) || Compile.IS_DEBUG } } diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index b994105de406..f3ad4b443ba3 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -472,6 +472,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") @@ -738,6 +740,8 @@ public final class DisplayManagerService extends SystemService { filter.addAction(Intent.ACTION_DOCK_EVENT); mContext.registerReceiver(mIdleModeReceiver, filter); + + mSmallAreaDetectionController = SmallAreaDetectionController.create(mContext); } @VisibleForTesting @@ -3128,6 +3132,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/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 53d1adfefbb9..fd42077bed7d 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -6183,6 +6183,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void onPackageReplaced(ApplicationInfo aInfo) { synchronized (mGlobalLock) { + // In case if setWindowManager hasn't been called yet when booting. + if (mRootWindowContainer == null) return; mRootWindowContainer.updateActivityApplicationInfo(aInfo); } } diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 2a995b24ef4f..ec5378f01ce3 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 97d7be6a718e..f6f673746609 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -67,6 +67,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; @@ -126,5 +127,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 fb14419a13c0..e28028f9fc2b 100644 --- a/services/tests/displayservicetests/Android.bp +++ b/services/tests/displayservicetests/Android.bp @@ -35,6 +35,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 40d7a774608b..a23539e37409 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -64,6 +64,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; @@ -113,6 +114,7 @@ import com.android.server.display.DisplayManagerService.SyncRoot; import com.android.server.display.feature.DisplayManagerFlags; 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; @@ -291,10 +293,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; @Mock DisplayManagerFlags mMockFlags; @@ -315,6 +318,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())); mResources = Mockito.spy(mContext.getResources()); 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()); + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java index 06033c7ebf75..3fcec963593c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java @@ -184,7 +184,7 @@ public class LetterboxConfigurationPersisterTest { LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT); firstPersister.setLetterboxPositionForVerticalReachability(false, LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP); - waitForCompletion(mPersisterQueue); + waitForCompletion(firstPersisterQueue); final int newPositionForHorizontalReachability = firstPersister.getLetterboxPositionForHorizontalReachability(false); final int newPositionForVerticalReachability = |