summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AconfigFlags.bp1
-rw-r--r--core/api/current.txt6
-rw-r--r--core/api/system-current.txt2
-rw-r--r--core/java/android/app/supervision/SupervisionManager.java23
-rw-r--r--core/java/android/hardware/location/ContextHubManager.java60
-rw-r--r--core/java/android/net/flags.aconfig8
-rw-r--r--core/java/android/os/Build.java17
-rw-r--r--core/java/android/os/IHintManager.aidl34
-rw-r--r--core/java/android/permission/flags.aconfig9
-rw-r--r--core/java/android/provider/Settings.java10
-rw-r--r--core/java/android/service/notification/ZenDeviceEffects.java169
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java47
-rw-r--r--core/java/android/service/notification/ZenModeDiff.java6
-rw-r--r--core/java/android/view/Choreographer.java143
-rw-r--r--core/java/android/view/ViewRootImpl.java1
-rw-r--r--core/java/android/window/BackProgressAnimator.java3
-rw-r--r--core/java/com/android/internal/widget/MessagingGroup.java25
-rw-r--r--core/jni/android_graphics_BLASTBufferQueue.cpp51
-rw-r--r--core/res/AndroidManifest.xml10
-rw-r--r--core/res/res/layout/notification_2025_template_header.xml1
-rw-r--r--core/res/res/values/config.xml3
-rw-r--r--core/res/res/values/config_telephony.xml6
-rw-r--r--core/res/res/values/public-staging.xml5
-rw-r--r--core/tests/coretests/src/android/os/BuildTest.java14
-rw-r--r--graphics/java/android/graphics/BLASTBufferQueue.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java10
-rw-r--r--media/java/android/media/MediaRoute2Info.java56
-rw-r--r--media/java/android/media/MediaRoute2ProviderInfo.java19
-rw-r--r--media/java/android/media/MediaRouter2.java15
-rw-r--r--media/java/android/media/MediaRouter2Manager.java19
-rw-r--r--media/java/android/media/flags/media_better_together.aconfig7
-rw-r--r--native/android/dynamic_instrumentation_manager.cpp3
-rw-r--r--native/android/include_platform/android/dynamic_instrumentation_manager.h46
-rw-r--r--native/android/performance_hint.cpp114
-rw-r--r--native/android/tests/performance_hint/PerformanceHintNativeTest.cpp35
-rw-r--r--nfc/Android.bp2
-rw-r--r--packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/SettingsSpinnerPreference.java4
-rw-r--r--packages/SettingsLib/res/values/arrays.xml21
-rw-r--r--packages/SettingsLib/res/values/strings.xml3
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt2
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt28
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationLockscreenScrim.kt4
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationScrimNestedScrollConnection.kt1
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackNestedScrollConnection.kt29
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt16
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt15
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt27
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt2
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt48
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt8
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt3
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt1
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt19
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt123
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt53
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt32
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt3
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt38
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/domain/interactor/KeyguardBypassInteractorTest.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java27
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt4
-rw-r--r--services/art-wear-profile2
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java20
-rw-r--r--services/core/java/com/android/server/app/GameManagerService.java18
-rw-r--r--services/core/java/com/android/server/app/GameManagerSettings.java8
-rw-r--r--services/core/java/com/android/server/display/BrightnessRangeController.java29
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java4
-rw-r--r--services/core/java/com/android/server/display/brightness/BrightnessEvent.java22
-rw-r--r--services/core/java/com/android/server/display/color/ColorDisplayService.java25
-rw-r--r--services/core/java/com/android/server/display/color/DisplayTransformManager.java6
-rw-r--r--services/core/java/com/android/server/display/feature/DisplayManagerFlags.java10
-rw-r--r--services/core/java/com/android/server/display/feature/display_flags.aconfig8
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java4
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java11
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java11
-rw-r--r--services/core/java/com/android/server/media/SystemMediaRoute2Provider.java66
-rw-r--r--services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java137
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java24
-rw-r--r--services/core/java/com/android/server/power/hint/HintManagerService.java126
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java18
-rw-r--r--services/core/java/com/android/server/wm/Transition.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java7
-rw-r--r--services/supervision/java/com/android/server/supervision/SupervisionService.java18
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/BrightnessRangeControllerTest.kt8
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java4
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessEventTest.java4
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/color/ColorDisplayServiceTest.java38
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/color/DisplayTransformManagerTest.java23
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java80
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java53
-rw-r--r--services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java145
-rw-r--r--services/tests/servicestests/src/com/android/server/app/GameManagerServiceSettingsTests.java30
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenDeviceEffectsTest.java42
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java39
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java35
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java32
107 files changed, 1640 insertions, 1087 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 45e33ce4b6e9..e40c78c494aa 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -401,6 +401,7 @@ java_aconfig_library {
min_sdk_version: "30",
apex_available: [
"//apex_available:platform",
+ "com.android.tethering",
"com.android.wifi",
],
defaults: ["framework-minus-apex-aconfig-java-defaults"],
diff --git a/core/api/current.txt b/core/api/current.txt
index f9e772649e43..ca4b2fae2f99 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -98,6 +98,7 @@ package android {
field public static final String DUMP = "android.permission.DUMP";
field public static final String ENFORCE_UPDATE_OWNERSHIP = "android.permission.ENFORCE_UPDATE_OWNERSHIP";
field public static final String EXECUTE_APP_ACTION = "android.permission.EXECUTE_APP_ACTION";
+ field @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public static final String EXECUTE_APP_FUNCTIONS = "android.permission.EXECUTE_APP_FUNCTIONS";
field public static final String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
field public static final String FACTORY_TEST = "android.permission.FACTORY_TEST";
field public static final String FOREGROUND_SERVICE = "android.permission.FOREGROUND_SERVICE";
@@ -8892,8 +8893,8 @@ package android.app.appfunctions {
}
@FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public final class AppFunctionManager {
- method @RequiresPermission(anyOf={"android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED", "android.permission.EXECUTE_APP_FUNCTIONS"}, conditional=true) public void executeAppFunction(@NonNull android.app.appfunctions.ExecuteAppFunctionRequest, @NonNull java.util.concurrent.Executor, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver<android.app.appfunctions.ExecuteAppFunctionResponse,android.app.appfunctions.AppFunctionException>);
- method @RequiresPermission(anyOf={"android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED", "android.permission.EXECUTE_APP_FUNCTIONS"}, conditional=true) public void isAppFunctionEnabled(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,java.lang.Exception>);
+ method @RequiresPermission(anyOf={"android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED", android.Manifest.permission.EXECUTE_APP_FUNCTIONS}, conditional=true) public void executeAppFunction(@NonNull android.app.appfunctions.ExecuteAppFunctionRequest, @NonNull java.util.concurrent.Executor, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver<android.app.appfunctions.ExecuteAppFunctionResponse,android.app.appfunctions.AppFunctionException>);
+ method @RequiresPermission(anyOf={"android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED", android.Manifest.permission.EXECUTE_APP_FUNCTIONS}, conditional=true) public void isAppFunctionEnabled(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,java.lang.Exception>);
method public void isAppFunctionEnabled(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,java.lang.Exception>);
method public void setAppFunctionEnabled(@NonNull String, int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,java.lang.Exception>);
field public static final int APP_FUNCTION_STATE_DEFAULT = 0; // 0x0
@@ -24940,6 +24941,7 @@ package android.media {
method @Nullable public android.net.Uri getIconUri();
method @NonNull public String getId();
method @NonNull public CharSequence getName();
+ method @FlaggedApi("com.android.media.flags.enable_media_route_2_info_provider_package_name") @Nullable public String getProviderPackageName();
method @FlaggedApi("com.android.media.flags.enable_route_visibility_control_api") @NonNull public java.util.List<java.util.Set<java.lang.String>> getRequiredPermissions();
method @FlaggedApi("com.android.media.flags.enable_built_in_speaker_route_suitability_statuses") public int getSuitabilityStatus();
method @FlaggedApi("com.android.media.flags.enable_mirroring_in_media_router_2") public int getSupportedRoutingTypes();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index e1d8fb11efb3..f0f0fc98881e 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -150,7 +150,6 @@ package android {
field @FlaggedApi("com.android.window.flags.untrusted_embedding_any_app_permission") public static final String EMBED_ANY_APP_IN_UNTRUSTED_MODE = "android.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE";
field @FlaggedApi("android.content.pm.emergency_install_permission") public static final String EMERGENCY_INSTALL_PACKAGES = "android.permission.EMERGENCY_INSTALL_PACKAGES";
field public static final String ENTER_CAR_MODE_PRIORITIZED = "android.permission.ENTER_CAR_MODE_PRIORITIZED";
- field @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public static final String EXECUTE_APP_FUNCTIONS = "android.permission.EXECUTE_APP_FUNCTIONS";
field @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public static final String EXECUTE_APP_FUNCTIONS_TRUSTED = "android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED";
field public static final String EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS = "android.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS";
field public static final String FORCE_BACK = "android.permission.FORCE_BACK";
@@ -523,7 +522,6 @@ package android {
field @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence_module") public static final int config_defaultOnDeviceIntelligenceDeviceConfigNamespace;
field @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence_module") public static final int config_defaultOnDeviceIntelligenceService;
field @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence_module") public static final int config_defaultOnDeviceSandboxedInferenceService;
- field @FlaggedApi("android.permission.flags.cross_user_role_platform_api_enabled") public static final int config_defaultReservedForTestingProfileGroupExclusivity;
field @FlaggedApi("android.permission.flags.retail_demo_role_enabled") public static final int config_defaultRetailDemo = 17039432; // 0x1040048
field public static final int config_defaultSms = 17039396; // 0x1040024
field @FlaggedApi("android.permission.flags.wallet_role_enabled") public static final int config_defaultWallet = 17039433; // 0x1040049
diff --git a/core/java/android/app/supervision/SupervisionManager.java b/core/java/android/app/supervision/SupervisionManager.java
index aee1cd9b4760..a5b58f968c27 100644
--- a/core/java/android/app/supervision/SupervisionManager.java
+++ b/core/java/android/app/supervision/SupervisionManager.java
@@ -16,8 +16,10 @@
package android.app.supervision;
+import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.annotation.UserHandleAware;
+import android.annotation.UserIdInt;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.RemoteException;
@@ -32,9 +34,7 @@ public class SupervisionManager {
private final Context mContext;
private final ISupervisionManager mService;
- /**
- * @hide
- */
+ /** @hide */
@UnsupportedAppUsage
public SupervisionManager(Context context, ISupervisionManager service) {
mContext = context;
@@ -48,8 +48,23 @@ public class SupervisionManager {
*/
@UserHandleAware
public boolean isSupervisionEnabled() {
+ return isSupervisionEnabledForUser(mContext.getUserId());
+ }
+
+ /**
+ * Returns whether the device is supervised.
+ *
+ * <p>The caller must be from the same user as the target or hold the {@link
+ * android.Manifest.permission#INTERACT_ACROSS_USERS} permission.
+ *
+ * @hide
+ */
+ @RequiresPermission(
+ value = android.Manifest.permission.INTERACT_ACROSS_USERS,
+ conditional = true)
+ public boolean isSupervisionEnabledForUser(@UserIdInt int userId) {
try {
- return mService.isSupervisionEnabledForUser(mContext.getUserId());
+ return mService.isSupervisionEnabledForUser(userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index d9888ad6cd8d..1e0cc94612dd 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -754,6 +754,7 @@ public final class ContextHubManager {
* @param executor the executor to invoke callbacks for this client
* @return the callback interface
*/
+ @FlaggedApi(Flags.FLAG_OFFLOAD_API)
private IContextHubEndpointDiscoveryCallback createDiscoveryCallback(
IHubEndpointDiscoveryCallback callback,
Executor executor,
@@ -767,21 +768,9 @@ public final class ContextHubManager {
}
executor.execute(
() -> {
- // TODO(b/380293951): Refactor
List<HubDiscoveryInfo> discoveryList =
- new ArrayList<>(hubEndpointInfoList.length);
- for (HubEndpointInfo info : hubEndpointInfoList) {
- if (serviceDescriptor != null) {
- for (HubServiceInfo sInfo : info.getServiceInfoCollection()) {
- if (sInfo.getServiceDescriptor()
- .equals(serviceDescriptor)) {
- discoveryList.add(new HubDiscoveryInfo(info, sInfo));
- }
- }
- } else {
- discoveryList.add(new HubDiscoveryInfo(info));
- }
- }
+ getMatchingEndpointDiscoveryList(
+ hubEndpointInfoList, serviceDescriptor);
if (discoveryList.isEmpty()) {
Log.w(TAG, "onEndpointsStarted: no matching service descriptor");
} else {
@@ -799,19 +788,8 @@ public final class ContextHubManager {
executor.execute(
() -> {
List<HubDiscoveryInfo> discoveryList =
- new ArrayList<>(hubEndpointInfoList.length);
- for (HubEndpointInfo info : hubEndpointInfoList) {
- if (serviceDescriptor != null) {
- for (HubServiceInfo sInfo : info.getServiceInfoCollection()) {
- if (sInfo.getServiceDescriptor()
- .equals(serviceDescriptor)) {
- discoveryList.add(new HubDiscoveryInfo(info, sInfo));
- }
- }
- } else {
- discoveryList.add(new HubDiscoveryInfo(info));
- }
- }
+ getMatchingEndpointDiscoveryList(
+ hubEndpointInfoList, serviceDescriptor);
if (discoveryList.isEmpty()) {
Log.w(TAG, "onEndpointsStopped: no matching service descriptor");
} else {
@@ -823,6 +801,34 @@ public final class ContextHubManager {
}
/**
+ * Generates a list of matching endpoint discovery info, given the list and an (optional)
+ * service descriptor. If service descriptor is null, all endpoints are added to the filtered
+ * output list.
+ *
+ * @param hubEndpointInfoList The hub endpoints to filter.
+ * @param serviceDescriptor The optional service descriptor to match, null if adding all
+ * endpoints.
+ * @return The list of filtered HubDiscoveryInfo which matches the serviceDescriptor.
+ */
+ @FlaggedApi(Flags.FLAG_OFFLOAD_API)
+ private List<HubDiscoveryInfo> getMatchingEndpointDiscoveryList(
+ HubEndpointInfo[] hubEndpointInfoList, @Nullable String serviceDescriptor) {
+ List<HubDiscoveryInfo> discoveryList = new ArrayList<>(hubEndpointInfoList.length);
+ for (HubEndpointInfo info : hubEndpointInfoList) {
+ if (serviceDescriptor != null) {
+ for (HubServiceInfo sInfo : info.getServiceInfoCollection()) {
+ if (sInfo.getServiceDescriptor().equals(serviceDescriptor)) {
+ discoveryList.add(new HubDiscoveryInfo(info, sInfo));
+ }
+ }
+ } else {
+ discoveryList.add(new HubDiscoveryInfo(info));
+ }
+ }
+ return discoveryList;
+ }
+
+ /**
* Equivalent to {@link #registerEndpointDiscoveryCallback(long, IHubEndpointDiscoveryCallback,
* Executor)} with the default executor in the main thread.
*/
diff --git a/core/java/android/net/flags.aconfig b/core/java/android/net/flags.aconfig
index 6799db3f7471..8d12b76e23ff 100644
--- a/core/java/android/net/flags.aconfig
+++ b/core/java/android/net/flags.aconfig
@@ -29,3 +29,11 @@ flag {
}
is_exported: true
}
+
+flag {
+ name: "mdns_improvement_for_25q2"
+ is_exported: true
+ namespace: "android_core_networking"
+ description: "Flag for MDNS quality, reliability and performance improvement in 25Q2"
+ bug: "373270045"
+}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 84ca5ed4ab10..d54dbad9286c 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1558,6 +1558,7 @@ public class Build {
* @hide
*/
@SuppressWarnings("FlaggedApi") // SDK_INT_MULTIPLIER is defined in this file
+ @SuppressLint("InlinedApi")
public static @SdkIntFull int parseFullVersion(@NonNull String version) {
int index = version.indexOf('.');
int major;
@@ -1569,12 +1570,22 @@ public class Build {
major = Integer.parseInt(version.substring(0, index));
minor = Integer.parseInt(version.substring(index + 1));
}
- if (major < 0 || minor < 0) {
- throw new NumberFormatException();
+ if (major < 0) {
+ throw new NumberFormatException("negative major version");
+ }
+ if (major >= 21474) {
+ throw new NumberFormatException("major version too large, must be less than 21474");
+ }
+ if (minor < 0) {
+ throw new NumberFormatException("negative minor version");
+ }
+ if (minor >= VERSION_CODES_FULL.SDK_INT_MULTIPLIER) {
+ throw new NumberFormatException("minor version too large, must be less than "
+ + VERSION_CODES_FULL.SDK_INT_MULTIPLIER);
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException("failed to parse '" + version
- + "' as a major.minor version code");
+ + "' as a major.minor version code", e);
}
return major * VERSION_CODES_FULL.SDK_INT_MULTIPLIER + minor;
}
diff --git a/core/java/android/os/IHintManager.aidl b/core/java/android/os/IHintManager.aidl
index 56a089aff78a..4a14a8d0faf8 100644
--- a/core/java/android/os/IHintManager.aidl
+++ b/core/java/android/os/IHintManager.aidl
@@ -21,13 +21,11 @@ import android.os.CpuHeadroomParamsInternal;
import android.os.GpuHeadroomParamsInternal;
import android.os.IHintSession;
import android.os.SessionCreationConfig;
-
-import android.hardware.power.ChannelConfig;
import android.hardware.power.CpuHeadroomResult;
+import android.hardware.power.ChannelConfig;
import android.hardware.power.GpuHeadroomResult;
import android.hardware.power.SessionConfig;
import android.hardware.power.SessionTag;
-import android.hardware.power.SupportInfo;
/** {@hide} */
interface IHintManager {
@@ -42,6 +40,11 @@ interface IHintManager {
IHintSession createHintSessionWithConfig(in IBinder token, in SessionTag tag,
in SessionCreationConfig creationConfig, out SessionConfig config);
+ /**
+ * Get preferred rate limit in nanoseconds.
+ */
+ long getHintSessionPreferredRate();
+
void setHintSessionThreads(in IHintSession hintSession, in int[] tids);
int[] getHintSessionThreadIds(in IHintSession hintSession);
@@ -58,28 +61,13 @@ interface IHintManager {
long getGpuHeadroomMinIntervalMillis();
/**
- * Used by the JNI to pass an interface to the SessionManager;
- * for internal use only.
+ * Get Maximum number of graphics pipeline threads allowed per-app.
*/
- oneway void passSessionManagerBinder(in IBinder sessionManager);
-
- parcelable HintManagerClientData {
- int powerHalVersion;
- int maxGraphicsPipelineThreads;
- long preferredRateNanos;
- SupportInfo supportInfo;
- }
-
- interface IHintManagerClient {
- /**
- * Returns FMQ channel information for the caller, which it associates to the callback binder lifespan.
- */
- oneway void receiveChannelConfig(in ChannelConfig config);
- }
+ int getMaxGraphicsPipelineThreadsCount();
/**
- * Set up an ADPF client, receiving a remote client binder interface and
- * passing back a bundle of support and configuration information.
+ * Used by the JNI to pass an interface to the SessionManager;
+ * for internal use only.
*/
- HintManagerClientData registerClient(in IHintManagerClient client);
+ oneway void passSessionManagerBinder(in IBinder sessionManager);
}
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index af96ccfee787..07b9f5242b42 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -467,15 +467,6 @@ flag {
}
flag {
- name: "cross_user_role_platform_api_enabled"
- is_exported: true
- is_fixed_read_only: true
- namespace: "permissions"
- description: "Enable cross-user roles platform API"
- bug: "367732307"
-}
-
-flag {
name: "rate_limit_batched_note_op_async_callbacks_enabled"
is_fixed_read_only: true
is_exported: true
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4acb6312f90d..cf0e90fb43ce 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2473,7 +2473,7 @@ public final class Settings {
* when a new SIM subscription has become available.
* <p>
* This Activity will only launch successfully if the newly active subscription ID is set as the
- * value of {@link EXTRA_SUB_ID} and the value corresponds with an active SIM subscription.
+ * value of {@link #EXTRA_SUB_ID} and the value corresponds with an active SIM subscription.
* <p>
* Input: {@link #EXTRA_SUB_ID}: the subscription ID of the newly active SIM subscription.
* <p>
@@ -13710,6 +13710,14 @@ public final class Settings {
"render_shadows_in_compositor";
/**
+ * Policy to be used for the display shade when connected to an external display.
+ * @hide
+ */
+ @Readable
+ public static final String DEVELOPMENT_SHADE_DISPLAY_AWARENESS =
+ "shade_display_awareness";
+
+ /**
* Path to the WindowManager display settings file. If unset, the default file path will
* be used.
*
diff --git a/core/java/android/service/notification/ZenDeviceEffects.java b/core/java/android/service/notification/ZenDeviceEffects.java
index 22b1be08e1db..06bd2555c2f8 100644
--- a/core/java/android/service/notification/ZenDeviceEffects.java
+++ b/core/java/android/service/notification/ZenDeviceEffects.java
@@ -42,21 +42,26 @@ public final class ZenDeviceEffects implements Parcelable {
/**
* Enum for the user-modifiable fields in this object.
+ *
* @hide
*/
- @IntDef(flag = true, prefix = { "FIELD_" }, value = {
- FIELD_GRAYSCALE,
- FIELD_SUPPRESS_AMBIENT_DISPLAY,
- FIELD_DIM_WALLPAPER,
- FIELD_NIGHT_MODE,
- FIELD_DISABLE_AUTO_BRIGHTNESS,
- FIELD_DISABLE_TAP_TO_WAKE,
- FIELD_DISABLE_TILT_TO_WAKE,
- FIELD_DISABLE_TOUCH,
- FIELD_MINIMIZE_RADIO_USAGE,
- FIELD_MAXIMIZE_DOZE,
- FIELD_EXTRA_EFFECTS
- })
+ @IntDef(
+ flag = true,
+ prefix = {"FIELD_"},
+ value = {
+ FIELD_GRAYSCALE,
+ FIELD_SUPPRESS_AMBIENT_DISPLAY,
+ FIELD_DIM_WALLPAPER,
+ FIELD_NIGHT_MODE,
+ FIELD_DISABLE_AUTO_BRIGHTNESS,
+ FIELD_DISABLE_TAP_TO_WAKE,
+ FIELD_DISABLE_TILT_TO_WAKE,
+ FIELD_DISABLE_TOUCH,
+ FIELD_MINIMIZE_RADIO_USAGE,
+ FIELD_MAXIMIZE_DOZE,
+ FIELD_NIGHT_LIGHT,
+ FIELD_EXTRA_EFFECTS
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface ModifiableField {}
@@ -105,6 +110,9 @@ public final class ZenDeviceEffects implements Parcelable {
*/
public static final int FIELD_EXTRA_EFFECTS = 1 << 10;
+ /** @hide */
+ public static final int FIELD_NIGHT_LIGHT = 1 << 11;
+
private static final int MAX_EFFECTS_LENGTH = 2_000; // characters
private final boolean mGrayscale;
@@ -118,12 +126,22 @@ public final class ZenDeviceEffects implements Parcelable {
private final boolean mDisableTouch;
private final boolean mMinimizeRadioUsage;
private final boolean mMaximizeDoze;
+ private final boolean mNightLight;
private final Set<String> mExtraEffects;
- private ZenDeviceEffects(boolean grayscale, boolean suppressAmbientDisplay,
- boolean dimWallpaper, boolean nightMode, boolean disableAutoBrightness,
- boolean disableTapToWake, boolean disableTiltToWake, boolean disableTouch,
- boolean minimizeRadioUsage, boolean maximizeDoze, Set<String> extraEffects) {
+ private ZenDeviceEffects(
+ boolean grayscale,
+ boolean suppressAmbientDisplay,
+ boolean dimWallpaper,
+ boolean nightMode,
+ boolean disableAutoBrightness,
+ boolean disableTapToWake,
+ boolean disableTiltToWake,
+ boolean disableTouch,
+ boolean minimizeRadioUsage,
+ boolean maximizeDoze,
+ boolean nightLight,
+ Set<String> extraEffects) {
mGrayscale = grayscale;
mSuppressAmbientDisplay = suppressAmbientDisplay;
mDimWallpaper = dimWallpaper;
@@ -134,6 +152,7 @@ public final class ZenDeviceEffects implements Parcelable {
mDisableTouch = disableTouch;
mMinimizeRadioUsage = minimizeRadioUsage;
mMaximizeDoze = maximizeDoze;
+ mNightLight = nightLight;
mExtraEffects = Collections.unmodifiableSet(extraEffects);
}
@@ -166,14 +185,25 @@ public final class ZenDeviceEffects implements Parcelable {
&& this.mDisableTouch == that.mDisableTouch
&& this.mMinimizeRadioUsage == that.mMinimizeRadioUsage
&& this.mMaximizeDoze == that.mMaximizeDoze
+ && this.mNightLight == that.mNightLight
&& Objects.equals(this.mExtraEffects, that.mExtraEffects);
}
@Override
public int hashCode() {
- return Objects.hash(mGrayscale, mSuppressAmbientDisplay, mDimWallpaper, mNightMode,
- mDisableAutoBrightness, mDisableTapToWake, mDisableTiltToWake, mDisableTouch,
- mMinimizeRadioUsage, mMaximizeDoze, mExtraEffects);
+ return Objects.hash(
+ mGrayscale,
+ mSuppressAmbientDisplay,
+ mDimWallpaper,
+ mNightMode,
+ mDisableAutoBrightness,
+ mDisableTapToWake,
+ mDisableTiltToWake,
+ mDisableTouch,
+ mMinimizeRadioUsage,
+ mMaximizeDoze,
+ mNightLight,
+ mExtraEffects);
}
@Override
@@ -189,6 +219,7 @@ public final class ZenDeviceEffects implements Parcelable {
if (mDisableTouch) effects.add("disableTouch");
if (mMinimizeRadioUsage) effects.add("minimizeRadioUsage");
if (mMaximizeDoze) effects.add("maximizeDoze");
+ if (mNightLight) effects.add("nightLight");
if (mExtraEffects.size() > 0) {
effects.add("extraEffects=[" + String.join(",", mExtraEffects) + "]");
}
@@ -228,6 +259,9 @@ public final class ZenDeviceEffects implements Parcelable {
if ((bitmask & FIELD_MAXIMIZE_DOZE) != 0) {
modified.add("FIELD_MAXIMIZE_DOZE");
}
+ if (((bitmask) & FIELD_NIGHT_LIGHT) != 0) {
+ modified.add("FIELD_NIGHT_LIGHT");
+ }
if ((bitmask & FIELD_EXTRA_EFFECTS) != 0) {
modified.add("FIELD_EXTRA_EFFECTS");
}
@@ -313,6 +347,15 @@ public final class ZenDeviceEffects implements Parcelable {
}
/**
+ * Whether the night display transformation should be activated while the rule is active.
+ *
+ * @hide
+ */
+ public boolean shouldUseNightLight() {
+ return mNightLight;
+ }
+
+ /**
* (Immutable) set of extra effects to be applied while the rule is active. Extra effects are
* not used in AOSP, but OEMs may add support for them by providing a custom
* {@link DeviceEffectsApplier}.
@@ -329,29 +372,46 @@ public final class ZenDeviceEffects implements Parcelable {
* @hide
*/
public boolean hasEffects() {
- return mGrayscale || mSuppressAmbientDisplay || mDimWallpaper || mNightMode
- || mDisableAutoBrightness || mDisableTapToWake || mDisableTiltToWake
- || mDisableTouch || mMinimizeRadioUsage || mMaximizeDoze
+ return mGrayscale
+ || mSuppressAmbientDisplay
+ || mDimWallpaper
+ || mNightMode
+ || mDisableAutoBrightness
+ || mDisableTapToWake
+ || mDisableTiltToWake
+ || mDisableTouch
+ || mMinimizeRadioUsage
+ || mMaximizeDoze
+ || mNightLight
|| mExtraEffects.size() > 0;
}
/** {@link Parcelable.Creator} that instantiates {@link ZenDeviceEffects} objects. */
@NonNull
- public static final Creator<ZenDeviceEffects> CREATOR = new Creator<ZenDeviceEffects>() {
- @Override
- public ZenDeviceEffects createFromParcel(Parcel in) {
- return new ZenDeviceEffects(in.readBoolean(),
- in.readBoolean(), in.readBoolean(), in.readBoolean(), in.readBoolean(),
- in.readBoolean(), in.readBoolean(), in.readBoolean(), in.readBoolean(),
- in.readBoolean(),
- Set.of(in.readArray(String.class.getClassLoader(), String.class)));
- }
-
- @Override
- public ZenDeviceEffects[] newArray(int size) {
- return new ZenDeviceEffects[size];
- }
- };
+ public static final Creator<ZenDeviceEffects> CREATOR =
+ new Creator<ZenDeviceEffects>() {
+ @Override
+ public ZenDeviceEffects createFromParcel(Parcel in) {
+ return new ZenDeviceEffects(
+ in.readBoolean(),
+ in.readBoolean(),
+ in.readBoolean(),
+ in.readBoolean(),
+ in.readBoolean(),
+ in.readBoolean(),
+ in.readBoolean(),
+ in.readBoolean(),
+ in.readBoolean(),
+ in.readBoolean(),
+ in.readBoolean(),
+ Set.of(in.readArray(String.class.getClassLoader(), String.class)));
+ }
+
+ @Override
+ public ZenDeviceEffects[] newArray(int size) {
+ return new ZenDeviceEffects[size];
+ }
+ };
@Override
public int describeContents() {
@@ -370,6 +430,7 @@ public final class ZenDeviceEffects implements Parcelable {
dest.writeBoolean(mDisableTouch);
dest.writeBoolean(mMinimizeRadioUsage);
dest.writeBoolean(mMaximizeDoze);
+ dest.writeBoolean(mNightLight);
dest.writeArray(mExtraEffects.toArray(new String[0]));
}
@@ -387,6 +448,7 @@ public final class ZenDeviceEffects implements Parcelable {
private boolean mDisableTouch;
private boolean mMinimizeRadioUsage;
private boolean mMaximizeDoze;
+ private boolean mNightLight;
private final HashSet<String> mExtraEffects = new HashSet<>();
/**
@@ -410,6 +472,7 @@ public final class ZenDeviceEffects implements Parcelable {
mDisableTouch = zenDeviceEffects.shouldDisableTouch();
mMinimizeRadioUsage = zenDeviceEffects.shouldMinimizeRadioUsage();
mMaximizeDoze = zenDeviceEffects.shouldMaximizeDoze();
+ mNightLight = zenDeviceEffects.shouldUseNightLight();
mExtraEffects.addAll(zenDeviceEffects.getExtraEffects());
}
@@ -512,6 +575,18 @@ public final class ZenDeviceEffects implements Parcelable {
}
/**
+ * Sets whether the night display transformation should be activated while the rule is
+ * active.
+ *
+ * @hide
+ */
+ @NonNull
+ public Builder setShouldUseNightLight(boolean nightLight) {
+ mNightLight = nightLight;
+ return this;
+ }
+
+ /**
* Sets the extra effects to be applied while the rule is active. Extra effects are not
* used in AOSP, but OEMs may add support for them by providing a custom
* {@link DeviceEffectsApplier}.
@@ -577,6 +652,7 @@ public final class ZenDeviceEffects implements Parcelable {
if (effects.shouldDisableTouch()) setShouldDisableTouch(true);
if (effects.shouldMinimizeRadioUsage()) setShouldMinimizeRadioUsage(true);
if (effects.shouldMaximizeDoze()) setShouldMaximizeDoze(true);
+ if (effects.shouldUseNightLight()) setShouldUseNightLight(true);
addExtraEffects(effects.getExtraEffects());
return this;
}
@@ -584,10 +660,19 @@ public final class ZenDeviceEffects implements Parcelable {
/** Builds a {@link ZenDeviceEffects} object based on the builder's state. */
@NonNull
public ZenDeviceEffects build() {
- return new ZenDeviceEffects(mGrayscale,
- mSuppressAmbientDisplay, mDimWallpaper, mNightMode, mDisableAutoBrightness,
- mDisableTapToWake, mDisableTiltToWake, mDisableTouch, mMinimizeRadioUsage,
- mMaximizeDoze, mExtraEffects);
+ return new ZenDeviceEffects(
+ mGrayscale,
+ mSuppressAmbientDisplay,
+ mDimWallpaper,
+ mNightMode,
+ mDisableAutoBrightness,
+ mDisableTapToWake,
+ mDisableTiltToWake,
+ mDisableTouch,
+ mMinimizeRadioUsage,
+ mMaximizeDoze,
+ mNightLight,
+ mExtraEffects);
}
}
}
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 13887781f1ec..4f459aa9131a 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -325,6 +325,7 @@ public class ZenModeConfig implements Parcelable {
private static final String DEVICE_EFFECT_DISABLE_TOUCH = "zdeDisableTouch";
private static final String DEVICE_EFFECT_MINIMIZE_RADIO_USAGE = "zdeMinimizeRadioUsage";
private static final String DEVICE_EFFECT_MAXIMIZE_DOZE = "zdeMaximizeDoze";
+ private static final String DEVICE_EFFECT_USE_NIGHT_LIGHT = "zdeUseNightLight";
private static final String DEVICE_EFFECT_EXTRAS = "zdeExtraEffects";
private static final String DEVICE_EFFECT_USER_MODIFIED_FIELDS = "zdeUserModifiedFields";
@@ -1508,25 +1509,32 @@ public class ZenModeConfig implements Parcelable {
@FlaggedApi(Flags.FLAG_MODES_API)
@Nullable
private static ZenDeviceEffects readZenDeviceEffectsXml(TypedXmlPullParser parser) {
- ZenDeviceEffects deviceEffects = new ZenDeviceEffects.Builder()
- .setShouldDisplayGrayscale(
- safeBoolean(parser, DEVICE_EFFECT_DISPLAY_GRAYSCALE, false))
- .setShouldSuppressAmbientDisplay(
- safeBoolean(parser, DEVICE_EFFECT_SUPPRESS_AMBIENT_DISPLAY, false))
- .setShouldDimWallpaper(safeBoolean(parser, DEVICE_EFFECT_DIM_WALLPAPER, false))
- .setShouldUseNightMode(safeBoolean(parser, DEVICE_EFFECT_USE_NIGHT_MODE, false))
- .setShouldDisableAutoBrightness(
- safeBoolean(parser, DEVICE_EFFECT_DISABLE_AUTO_BRIGHTNESS, false))
- .setShouldDisableTapToWake(
- safeBoolean(parser, DEVICE_EFFECT_DISABLE_TAP_TO_WAKE, false))
- .setShouldDisableTiltToWake(
- safeBoolean(parser, DEVICE_EFFECT_DISABLE_TILT_TO_WAKE, false))
- .setShouldDisableTouch(safeBoolean(parser, DEVICE_EFFECT_DISABLE_TOUCH, false))
- .setShouldMinimizeRadioUsage(
- safeBoolean(parser, DEVICE_EFFECT_MINIMIZE_RADIO_USAGE, false))
- .setShouldMaximizeDoze(safeBoolean(parser, DEVICE_EFFECT_MAXIMIZE_DOZE, false))
- .setExtraEffects(safeStringSet(parser, DEVICE_EFFECT_EXTRAS))
- .build();
+ ZenDeviceEffects deviceEffects =
+ new ZenDeviceEffects.Builder()
+ .setShouldDisplayGrayscale(
+ safeBoolean(parser, DEVICE_EFFECT_DISPLAY_GRAYSCALE, false))
+ .setShouldSuppressAmbientDisplay(
+ safeBoolean(parser, DEVICE_EFFECT_SUPPRESS_AMBIENT_DISPLAY, false))
+ .setShouldDimWallpaper(
+ safeBoolean(parser, DEVICE_EFFECT_DIM_WALLPAPER, false))
+ .setShouldUseNightMode(
+ safeBoolean(parser, DEVICE_EFFECT_USE_NIGHT_MODE, false))
+ .setShouldDisableAutoBrightness(
+ safeBoolean(parser, DEVICE_EFFECT_DISABLE_AUTO_BRIGHTNESS, false))
+ .setShouldDisableTapToWake(
+ safeBoolean(parser, DEVICE_EFFECT_DISABLE_TAP_TO_WAKE, false))
+ .setShouldDisableTiltToWake(
+ safeBoolean(parser, DEVICE_EFFECT_DISABLE_TILT_TO_WAKE, false))
+ .setShouldDisableTouch(
+ safeBoolean(parser, DEVICE_EFFECT_DISABLE_TOUCH, false))
+ .setShouldMinimizeRadioUsage(
+ safeBoolean(parser, DEVICE_EFFECT_MINIMIZE_RADIO_USAGE, false))
+ .setShouldMaximizeDoze(
+ safeBoolean(parser, DEVICE_EFFECT_MAXIMIZE_DOZE, false))
+ .setShouldUseNightLight(
+ safeBoolean(parser, DEVICE_EFFECT_USE_NIGHT_LIGHT, false))
+ .setExtraEffects(safeStringSet(parser, DEVICE_EFFECT_EXTRAS))
+ .build();
return deviceEffects.hasEffects() ? deviceEffects : null;
}
@@ -1550,6 +1558,7 @@ public class ZenModeConfig implements Parcelable {
writeBooleanIfTrue(out, DEVICE_EFFECT_MINIMIZE_RADIO_USAGE,
deviceEffects.shouldMinimizeRadioUsage());
writeBooleanIfTrue(out, DEVICE_EFFECT_MAXIMIZE_DOZE, deviceEffects.shouldMaximizeDoze());
+ writeBooleanIfTrue(out, DEVICE_EFFECT_USE_NIGHT_LIGHT, deviceEffects.shouldUseNightLight());
writeStringSet(out, DEVICE_EFFECT_EXTRAS, deviceEffects.getExtraEffects());
}
diff --git a/core/java/android/service/notification/ZenModeDiff.java b/core/java/android/service/notification/ZenModeDiff.java
index c9f464716e72..31acd248dcc0 100644
--- a/core/java/android/service/notification/ZenModeDiff.java
+++ b/core/java/android/service/notification/ZenModeDiff.java
@@ -714,6 +714,7 @@ public class ZenModeDiff {
public static final String FIELD_DISABLE_TOUCH = "mDisableTouch";
public static final String FIELD_MINIMIZE_RADIO_USAGE = "mMinimizeRadioUsage";
public static final String FIELD_MAXIMIZE_DOZE = "mMaximizeDoze";
+ public static final String FIELD_NIGHT_LIGHT = "mNightLight";
public static final String FIELD_EXTRA_EFFECTS = "mExtraEffects";
// NOTE: new field strings must match the variable names in ZenDeviceEffects
@@ -781,6 +782,11 @@ public class ZenModeDiff {
addField(FIELD_MAXIMIZE_DOZE, new FieldDiff<>(from.shouldMaximizeDoze(),
to.shouldMaximizeDoze()));
}
+ if (from.shouldUseNightLight() != to.shouldUseNightLight()) {
+ addField(
+ FIELD_NIGHT_LIGHT,
+ new FieldDiff<>(from.shouldUseNightLight(), to.shouldUseNightLight()));
+ }
if (!Objects.equals(from.getExtraEffects(), to.getExtraEffects())) {
addField(FIELD_EXTRA_EFFECTS, new FieldDiff<>(from.getExtraEffects(),
to.getExtraEffects()));
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 8cb96ae1d611..089b5c256b6e 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -42,6 +42,7 @@ import android.view.animation.AnimationUtils;
import java.io.PrintWriter;
import java.util.Locale;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Coordinates the timing of animations, input and drawing.
@@ -208,7 +209,7 @@ public final class Choreographer {
private final FrameData mFrameData = new FrameData();
private volatile boolean mInDoFrameCallback = false;
- private static class BufferStuffingData {
+ private static class BufferStuffingState {
enum RecoveryAction {
// No recovery
NONE,
@@ -218,21 +219,15 @@ public final class Choreographer {
// back toward threshold.
DELAY_FRAME
}
- // The maximum number of times frames will be delayed per buffer stuffing event.
- // Since buffer stuffing can persist for several consecutive frames following the
- // initial missed frame, we want to adjust the timeline with enough frame delays and
- // offsets to return the queued buffer count back to threshold.
- public static final int MAX_FRAME_DELAYS = 3;
+ // Indicates if recovery should begin. Is true whenever the client was blocked
+ // on dequeuing a buffer. When buffer stuffing recovery begins, this is reset
+ // since the scheduled frame delay reduces the number of queued buffers.
+ public AtomicBoolean isStuffed = new AtomicBoolean(false);
// Whether buffer stuffing recovery has begun. Recovery can only end
// when events are idle.
public boolean isRecovering = false;
- // The number of frames delayed so far during recovery. Used to compare with
- // MAX_FRAME_DELAYS to safeguard against excessive frame delays during recovery.
- // Also used as unique cookie for tracing.
- public int numberFrameDelays = 0;
-
// The number of additional frame delays scheduled during recovery to wait for the next
// vsync. These are scheduled when frame times appear to go backward or frames are
// being skipped due to FPSDivisor.
@@ -245,12 +240,20 @@ public final class Choreographer {
*/
public void reset() {
isRecovering = false;
- numberFrameDelays = 0;
numberWaitsForNextVsync = 0;
}
}
- private final BufferStuffingData mBufferStuffingData = new BufferStuffingData();
+ private final BufferStuffingState mBufferStuffingState = new BufferStuffingState();
+
+ /**
+ * Set flag to indicate that client is blocked waiting for buffer release and
+ * buffer stuffing recovery should soon begin.
+ * @hide
+ */
+ public void onWaitForBufferRelease() {
+ mBufferStuffingState.isStuffed.set(true);
+ }
/**
* Contains information about the current frame for jank-tracking,
@@ -901,67 +904,56 @@ public final class Choreographer {
// Conducts logic for beginning or ending buffer stuffing recovery.
// Returns an enum for the recovery action that should be taken in doFrame().
- BufferStuffingData.RecoveryAction checkBufferStuffingRecovery(long frameTimeNanos,
+ BufferStuffingState.RecoveryAction updateBufferStuffingState(long frameTimeNanos,
DisplayEventReceiver.VsyncEventData vsyncEventData) {
- // Canned animations can recover from buffer stuffing whenever more
- // than 2 buffers are queued.
- if (vsyncEventData.numberQueuedBuffers > 2) {
- mBufferStuffingData.isRecovering = true;
- // Intentional frame delay that can happen at most MAX_FRAME_DELAYS times per
- // buffer stuffing event until the buffer count returns to threshold. The
- // delayed frames are compensated for by the negative offsets added to the
- // animation timestamps.
- if (mBufferStuffingData.numberFrameDelays < mBufferStuffingData.MAX_FRAME_DELAYS) {
- if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
- Trace.asyncTraceForTrackBegin(
- Trace.TRACE_TAG_VIEW, "Buffer stuffing recovery", "Thread "
- + android.os.Process.myTid() + ", recover frame #"
- + mBufferStuffingData.numberFrameDelays,
- mBufferStuffingData.numberFrameDelays);
- }
- mBufferStuffingData.numberFrameDelays++;
- scheduleVsyncLocked();
- return BufferStuffingData.RecoveryAction.DELAY_FRAME;
+ if (!mBufferStuffingState.isRecovering) {
+ if (!mBufferStuffingState.isStuffed.getAndSet(false)) {
+ return BufferStuffingState.RecoveryAction.NONE;
+ }
+ // Canned animations can recover from buffer stuffing whenever the
+ // client is blocked on dequeueBuffer. Frame delay only occurs at
+ // the start of recovery to free a buffer.
+ mBufferStuffingState.isRecovering = true;
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ Trace.asyncTraceForTrackBegin(
+ Trace.TRACE_TAG_VIEW, "Buffer stuffing recovery", "Thread "
+ + android.os.Process.myTid() + ", recover frame", 0);
}
+ return BufferStuffingState.RecoveryAction.DELAY_FRAME;
}
- if (mBufferStuffingData.isRecovering) {
- // Includes an additional expected frame delay from the natural scheduling
- // of the next vsync event.
- int totalFrameDelays = mBufferStuffingData.numberFrameDelays
- + mBufferStuffingData.numberWaitsForNextVsync + 1;
- long vsyncsSinceLastCallback = mLastFrameIntervalNanos > 0
- ? (frameTimeNanos - mLastNoOffsetFrameTimeNanos) / mLastFrameIntervalNanos : 0;
-
- // Detected idle state due to a longer inactive period since the last vsync callback
- // than the total expected number of vsync frame delays. End buffer stuffing recovery.
- // There are no frames to animate and offsets no longer need to be added
- // since the idle state gives the animation a chance to catch up.
- if (vsyncsSinceLastCallback > totalFrameDelays) {
- if (DEBUG_JANK) {
- Log.d(TAG, "End buffer stuffing recovery");
- }
- if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
- for (int i = 0; i < mBufferStuffingData.numberFrameDelays; i++) {
- Trace.asyncTraceForTrackEnd(
- Trace.TRACE_TAG_VIEW, "Buffer stuffing recovery", i);
- }
- }
- mBufferStuffingData.reset();
-
- } else {
- if (DEBUG_JANK) {
- Log.d(TAG, "Adjust animation timeline with a negative offset");
- }
- if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
- Trace.instantForTrack(
- Trace.TRACE_TAG_VIEW, "Buffer stuffing recovery",
- "Negative offset added to animation");
- }
- return BufferStuffingData.RecoveryAction.OFFSET;
+ // Total number of frame delays used to detect idle state. Includes an additional
+ // expected frame delay from the natural scheduling of the next vsync event and
+ // the intentional frame delay that was scheduled when stuffing was first detected.
+ int totalFrameDelays = mBufferStuffingState.numberWaitsForNextVsync + 2;
+ long vsyncsSinceLastCallback = mLastFrameIntervalNanos > 0
+ ? (frameTimeNanos - mLastNoOffsetFrameTimeNanos) / mLastFrameIntervalNanos : 0;
+
+ // Detected idle state due to a longer inactive period since the last vsync callback
+ // than the total expected number of vsync frame delays. End buffer stuffing recovery.
+ // There are no frames to animate and offsets no longer need to be added
+ // since the idle state gives the animation a chance to catch up.
+ if (vsyncsSinceLastCallback > totalFrameDelays) {
+ if (DEBUG_JANK) {
+ Log.d(TAG, "End buffer stuffing recovery");
}
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ Trace.asyncTraceForTrackEnd(
+ Trace.TRACE_TAG_VIEW, "Buffer stuffing recovery", 0);
+ }
+ mBufferStuffingState.reset();
+ return BufferStuffingState.RecoveryAction.NONE;
+ }
+
+ if (DEBUG_JANK) {
+ Log.d(TAG, "Adjust animation timeline with a negative offset");
+ }
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ Trace.instantForTrack(
+ Trace.TRACE_TAG_VIEW, "Buffer stuffing recovery",
+ "Negative offset added to animation");
}
- return BufferStuffingData.RecoveryAction.NONE;
+ return BufferStuffingState.RecoveryAction.OFFSET;
}
void doFrame(long frameTimeNanos, int frame,
@@ -973,7 +965,7 @@ public final class Choreographer {
// Evaluate if buffer stuffing recovery needs to start or end, and
// what actions need to be taken for recovery.
- switch (checkBufferStuffingRecovery(frameTimeNanos, vsyncEventData)) {
+ switch (updateBufferStuffingState(frameTimeNanos, vsyncEventData)) {
case NONE:
// Without buffer stuffing recovery, offsetFrameTimeNanos is
// synonymous with frameTimeNanos.
@@ -984,7 +976,8 @@ public final class Choreographer {
offsetFrameTimeNanos = frameTimeNanos - frameIntervalNanos;
break;
case DELAY_FRAME:
- // Intentional frame delay to help restore queued buffer count to threshold.
+ // Intentional frame delay to help reduce queued buffer count.
+ scheduleVsyncLocked();
return;
default:
break;
@@ -1037,7 +1030,7 @@ public final class Choreographer {
+ " ms in the past.");
}
}
- if (mBufferStuffingData.isRecovering) {
+ if (mBufferStuffingState.isRecovering) {
frameTimeNanos -= frameIntervalNanos;
if (DEBUG_JANK) {
Log.d(TAG, "Adjusted animation timeline with a negative offset after"
@@ -1055,8 +1048,8 @@ public final class Choreographer {
+ "previously skipped frame. Waiting for next vsync.");
}
traceMessage("Frame time goes backward");
- if (mBufferStuffingData.isRecovering) {
- mBufferStuffingData.numberWaitsForNextVsync++;
+ if (mBufferStuffingState.isRecovering) {
+ mBufferStuffingState.numberWaitsForNextVsync++;
}
scheduleVsyncLocked();
return;
@@ -1066,8 +1059,8 @@ public final class Choreographer {
long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
if (timeSinceVsync < (frameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
traceMessage("Frame skipped due to FPSDivisor");
- if (mBufferStuffingData.isRecovering) {
- mBufferStuffingData.numberWaitsForNextVsync++;
+ if (mBufferStuffingState.isRecovering) {
+ mBufferStuffingState.numberWaitsForNextVsync++;
}
scheduleVsyncLocked();
return;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index c1b92ee3f74e..609f1ef06612 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2772,6 +2772,7 @@ public final class ViewRootImpl implements ViewParent,
mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
mSurfaceSize.x, mSurfaceSize.y, mWindowAttributes.format);
mBlastBufferQueue.setTransactionHangCallback(sTransactionHangCallback);
+ mBlastBufferQueue.setWaitForBufferReleaseCallback(mChoreographer::onWaitForBufferRelease);
// If we create and destroy BBQ without recreating the SurfaceControl, we can end up
// queuing buffers on multiple apply tokens causing out of order buffer submissions. We
// fix this by setting the same apply token on all BBQs created by this VRI.
diff --git a/core/java/android/window/BackProgressAnimator.java b/core/java/android/window/BackProgressAnimator.java
index b535effd393a..f61eb30d3171 100644
--- a/core/java/android/window/BackProgressAnimator.java
+++ b/core/java/android/window/BackProgressAnimator.java
@@ -52,6 +52,7 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL
*/
private static final float SCALE_FACTOR = 100f;
private static final float FLING_FRICTION = 8f;
+ private static final float BUTTON_SPRING_STIFFNESS = 100;
private final SpringAnimation mSpring;
private ProgressCallback mCallback;
private float mProgress = 0;
@@ -156,7 +157,7 @@ public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateL
/* frameTime */ System.nanoTime() / TimeUtils.NANOS_PER_MS);
if (predictiveBackSwipeEdgeNoneApi()) {
if (event.getSwipeEdge() == EDGE_NONE) {
- mButtonSpringForce.setStiffness(SpringForce.STIFFNESS_LOW);
+ mButtonSpringForce.setStiffness(BUTTON_SPRING_STIFFNESS);
mSpring.setSpring(mButtonSpringForce);
mSpring.animateToFinalPosition(SCALE_FACTOR);
} else {
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index 169a9e8585b0..31d9770f6ac4 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -448,6 +448,17 @@ public class MessagingGroup extends NotificationOptimizedLinearLayout implements
mSenderView.setVisibility(hidden ? GONE : VISIBLE);
}
+ private void updateIconVisibility() {
+ if (Flags.notificationsRedesignTemplates() && !mIsInConversation) {
+ // We don't show any icon (other than the app icon) in the collapsed form. For
+ // conversations, keeping this container helps with aligning the message to the icon
+ // when collapsed, but the old messaging style already has this alignment built into
+ // the template like all other layouts. Conversations are special because we use the
+ // same base layout for both the collapsed and expanded views.
+ mMessagingIconContainer.setVisibility(mSingleLine ? GONE : VISIBLE);
+ }
+ }
+
@Override
public boolean hasDifferentHeightWhenFirst() {
return mCanHideSenderIfFirst && !mSingleLine && !TextUtils.isEmpty(mSenderName);
@@ -703,6 +714,7 @@ public class MessagingGroup extends NotificationOptimizedLinearLayout implements
updateMaxDisplayedLines();
updateClipRect();
updateSenderVisibility();
+ updateIconVisibility();
}
}
@@ -716,13 +728,16 @@ public class MessagingGroup extends NotificationOptimizedLinearLayout implements
* @param isInConversation is this in a conversation
*/
public void setIsInConversation(boolean isInConversation) {
- if (Flags.notificationsRedesignTemplates()) {
- // No alignment adjustments are necessary in the redesign, as the size of the icons
- // in both conversations and old messaging notifications are the same.
- return;
- }
if (mIsInConversation != isInConversation) {
mIsInConversation = isInConversation;
+
+ if (Flags.notificationsRedesignTemplates()) {
+ updateIconVisibility();
+ // No other alignment adjustments are necessary in the redesign, as the size of the
+ // icons in both conversations and old messaging notifications are the same.
+ return;
+ }
+
MarginLayoutParams layoutParams =
(MarginLayoutParams) mMessagingIconContainer.getLayoutParams();
layoutParams.width = mIsInConversation
diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp
index b9c3bf73f11c..7b61a5db0b41 100644
--- a/core/jni/android_graphics_BLASTBufferQueue.cpp
+++ b/core/jni/android_graphics_BLASTBufferQueue.cpp
@@ -87,6 +87,38 @@ private:
jobject mTransactionHangObject;
};
+struct {
+ jmethodID onWaitForBufferRelease;
+} gWaitForBufferReleaseCallback;
+
+class WaitForBufferReleaseCallbackWrapper
+ : public LightRefBase<WaitForBufferReleaseCallbackWrapper> {
+public:
+ explicit WaitForBufferReleaseCallbackWrapper(JNIEnv* env, jobject jobject) {
+ env->GetJavaVM(&mVm);
+ mWaitForBufferReleaseObject = env->NewGlobalRef(jobject);
+ LOG_ALWAYS_FATAL_IF(!mWaitForBufferReleaseObject, "Failed to make global ref");
+ }
+
+ ~WaitForBufferReleaseCallbackWrapper() {
+ if (mWaitForBufferReleaseObject != nullptr) {
+ getenv(mVm)->DeleteGlobalRef(mWaitForBufferReleaseObject);
+ mWaitForBufferReleaseObject = nullptr;
+ }
+ }
+
+ void onWaitForBufferRelease() {
+ JNIEnv* env = getenv(mVm);
+ getenv(mVm)->CallVoidMethod(mWaitForBufferReleaseObject,
+ gWaitForBufferReleaseCallback.onWaitForBufferRelease);
+ DieIfException(env, "Uncaught exception in WaitForBufferReleaseCallback.");
+ }
+
+private:
+ JavaVM* mVm;
+ jobject mWaitForBufferReleaseObject;
+};
+
static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName,
jboolean updateDestinationFrame) {
ScopedUtfChars name(env, jName);
@@ -215,6 +247,18 @@ static void nativeSetApplyToken(JNIEnv* env, jclass clazz, jlong ptr, jobject ap
return queue->setApplyToken(std::move(token));
}
+static void nativeSetWaitForBufferReleaseCallback(JNIEnv* env, jclass clazz, jlong ptr,
+ jobject waitForBufferReleaseCallback) {
+ sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
+ if (waitForBufferReleaseCallback == nullptr) {
+ queue->setWaitForBufferReleaseCallback(nullptr);
+ } else {
+ sp<WaitForBufferReleaseCallbackWrapper> wrapper =
+ new WaitForBufferReleaseCallbackWrapper{env, waitForBufferReleaseCallback};
+ queue->setWaitForBufferReleaseCallback([wrapper]() { wrapper->onWaitForBufferRelease(); });
+ }
+}
+
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
// clang-format off
@@ -234,6 +278,9 @@ static const JNINativeMethod gMethods[] = {
"(JLandroid/graphics/BLASTBufferQueue$TransactionHangCallback;)V",
(void*)nativeSetTransactionHangCallback},
{"nativeSetApplyToken", "(JLandroid/os/IBinder;)V", (void*)nativeSetApplyToken},
+ {"nativeSetWaitForBufferReleaseCallback",
+ "(JLandroid/graphics/BLASTBufferQueue$WaitForBufferReleaseCallback;)V",
+ (void*)nativeSetWaitForBufferReleaseCallback},
// clang-format on
};
@@ -255,6 +302,10 @@ int register_android_graphics_BLASTBufferQueue(JNIEnv* env) {
gTransactionHangCallback.onTransactionHang =
GetMethodIDOrDie(env, transactionHangClass, "onTransactionHang",
"(Ljava/lang/String;)V");
+ jclass waitForBufferReleaseClass =
+ FindClassOrDie(env, "android/graphics/BLASTBufferQueue$WaitForBufferReleaseCallback");
+ gWaitForBufferReleaseCallback.onWaitForBufferRelease =
+ GetMethodIDOrDie(env, waitForBufferReleaseClass, "onWaitForBufferRelease", "()V");
return 0;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 82cad8b3a477..4a948dd91fb0 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -8307,20 +8307,21 @@
android:featureFlag="android.app.appfunctions.flags.enable_app_function_manager"
android:protectionLevel="signature" />
- <!-- @SystemApi Allows a trusted application to perform actions on behalf of users inside of
+ <!-- Allows a trusted application to perform actions on behalf of users inside of
applications with privacy guarantees from the system.
<p>This permission is currently only granted to system packages in the
{@link android.app.role.SYSTEM_UI_INTELLIGENCE} role which complies with privacy
requirements outlined in the Android CDD section "9.8.6 Content Capture".
<p>Apps are not able to opt-out from caller having this permission.
<p>Protection level: internal|role
+ @SystemApi
@hide
- @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") -->
+ @FlaggedApi(android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER) -->
<permission android:name="android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED"
android:featureFlag="android.app.appfunctions.flags.enable_app_function_manager"
android:protectionLevel="internal|role" />
- <!-- @SystemApi Allows an application to perform actions on behalf of users inside of
+ <!-- Allows an application to perform actions on behalf of users inside of
applications.
<p>This permission is currently only granted to preinstalled / system apps having the
{@link android.app.role.ASSISTANT} role.
@@ -8328,8 +8329,7 @@
limiting to only callers with {@link android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED}
instead.
<p>Protection level: internal|role
- @hide
- @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") -->
+ @FlaggedApi(android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER) -->
<permission android:name="android.permission.EXECUTE_APP_FUNCTIONS"
android:featureFlag="android.app.appfunctions.flags.enable_app_function_manager"
android:protectionLevel="internal|role" />
diff --git a/core/res/res/layout/notification_2025_template_header.xml b/core/res/res/layout/notification_2025_template_header.xml
index 63872aff8dd0..fc727e1c72f5 100644
--- a/core/res/res/layout/notification_2025_template_header.xml
+++ b/core/res/res/layout/notification_2025_template_header.xml
@@ -20,7 +20,6 @@
android:id="@+id/notification_header"
android:layout_width="match_parent"
android:layout_height="@dimen/notification_2025_header_height"
- android:layout_marginBottom="@dimen/notification_header_margin_bottom"
android:clipChildren="false"
android:gravity="center_vertical"
android:orientation="horizontal"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 89184bcc3721..3d023c3e1d11 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2466,9 +2466,6 @@
<string name="config_systemCallStreaming" translatable="false"></string>
<!-- The name of the package that will hold the default retail demo role. -->
<string name="config_defaultRetailDemo" translatable="false"></string>
- <!-- The name of the package that will hold the default reserved for testing profile group
- exclusivity role. -->
- <string name="config_defaultReservedForTestingProfileGroupExclusivity" translatable="false">android.app.rolemultiuser.cts.app</string>
<!-- The component name of the wear service class that will be started by the system server. -->
<string name="config_wearServiceComponent" translatable="false"></string>
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 196da29127df..20ae29659783 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -471,6 +471,12 @@
<string name="satellite_access_config_file" translatable="false"></string>
<java-symbol type="string" name="satellite_access_config_file" />
+ <!-- A string defines the NIDD (Non-IP Data Delivery) APN to be used for satellite attachment. For more on NIDD,
+ see 3GPP TS 29.542. This config is used for an NTN-only subscription, which requires activation before being used.
+ -->
+ <string name="config_satellite_nidd_apn_name" translatable="false"></string>
+ <java-symbol type="string" name="config_satellite_nidd_apn_name" />
+
<!-- Boolean indicating whether to enable MT SMS polling for NB IOT NTN. -->
<bool name="config_enabled_mt_sms_polling">true</bool>
<java-symbol type="bool" name="config_enabled_mt_sms_polling" />
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index 8259ce3c0aee..e82992b91783 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -151,9 +151,8 @@
<!-- @FlaggedApi(android.content.pm.Flags.FLAG_SDK_DEPENDENCY_INSTALLER)
@hide @SystemApi -->
<public name="config_systemDependencyInstaller" />
- <!-- @FlaggedApi(android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_PLATFORM_API_ENABLED)
- @hide @SystemApi -->
- <public name="config_defaultReservedForTestingProfileGroupExclusivity" />
+ <!-- @hide @SystemApi -->
+ <public name="removed_config_defaultReservedForTestingProfileGroupExclusivity" />
<!-- @FlaggedApi(android.permission.flags.Flags.FLAG_SYSTEM_VENDOR_INTELLIGENCE_ROLE_ENABLED)
@hide @SystemApi -->
<public name="config_systemVendorIntelligence" />
diff --git a/core/tests/coretests/src/android/os/BuildTest.java b/core/tests/coretests/src/android/os/BuildTest.java
index 2a67716aa215..0bbfb6566d00 100644
--- a/core/tests/coretests/src/android/os/BuildTest.java
+++ b/core/tests/coretests/src/android/os/BuildTest.java
@@ -178,6 +178,20 @@ public class BuildTest {
}
@Test
+ public void testParseFullVersionIncorrectInputMajorVersionTooLarge() throws Exception {
+ assertThrows(IllegalArgumentException.class, () -> {
+ Build.parseFullVersion("40000.1");
+ });
+ }
+
+ @Test
+ public void testParseFullVersionIncorrectInputMinorVersionTooLarge() throws Exception {
+ assertThrows(IllegalArgumentException.class, () -> {
+ Build.parseFullVersion("3.99999999");
+ });
+ }
+
+ @Test
public void testFullVersionToStringCorrectInput() throws Exception {
assertEquals("0.0", Build.fullVersionToString(0));
assertEquals("1.0", Build.fullVersionToString(1 * 100000 + 0));
diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java
index 90723b2f1493..906c71d9caca 100644
--- a/graphics/java/android/graphics/BLASTBufferQueue.java
+++ b/graphics/java/android/graphics/BLASTBufferQueue.java
@@ -49,11 +49,22 @@ public final class BLASTBufferQueue {
private static native void nativeSetTransactionHangCallback(long ptr,
TransactionHangCallback callback);
private static native void nativeSetApplyToken(long ptr, IBinder applyToken);
+ private static native void nativeSetWaitForBufferReleaseCallback(long ptr,
+ WaitForBufferReleaseCallback callback);
public interface TransactionHangCallback {
void onTransactionHang(String reason);
}
+
+ public interface WaitForBufferReleaseCallback {
+ /**
+ * Indicates that the client is waiting on buffer release
+ * due to no free buffers being available to render into.
+ */
+ void onWaitForBufferRelease();
+ }
+
/** Create a new connection with the surface flinger. */
public BLASTBufferQueue(String name, SurfaceControl sc, int width, int height,
@PixelFormat.Format int format) {
@@ -210,4 +221,11 @@ public final class BLASTBufferQueue {
public void setApplyToken(IBinder applyToken) {
nativeSetApplyToken(mNativeObject, applyToken);
}
+
+ /**
+ * Propagate callback about being blocked on buffer release.
+ */
+ public void setWaitForBufferReleaseCallback(WaitForBufferReleaseCallback waitCallback) {
+ nativeSetWaitForBufferReleaseCallback(mNativeObject, waitCallback);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 56efdb885512..ddc107e0dbc4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -1106,11 +1106,13 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
mCurrentTracker.updateStartLocation();
BackMotionEvent startEvent = mCurrentTracker.createStartEvent(mApps[0]);
dispatchOnBackStarted(mActiveCallback, startEvent);
- // TODO(b/373544911): onBackStarted is dispatched here so that
- // WindowOnBackInvokedDispatcher knows about the back navigation and intercepts touch
- // events while it's active. It would be cleaner and safer to disable multitouch
- // altogether (same as in gesture-nav).
- dispatchOnBackStarted(mBackNavigationInfo.getOnBackInvokedCallback(), startEvent);
+ if (startEvent.getSwipeEdge() == EDGE_NONE) {
+ // TODO(b/373544911): onBackStarted is dispatched here so that
+ // WindowOnBackInvokedDispatcher knows about the back navigation and intercepts
+ // touch events while it's active. It would be cleaner and safer to disable
+ // multitouch altogether (same as in gesture-nav).
+ dispatchOnBackStarted(mBackNavigationInfo.getOnBackInvokedCallback(), startEvent);
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index e48c887c625f..d0c21c9ec7c0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -20,6 +20,7 @@ import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_A
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
@@ -145,6 +146,7 @@ import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.shared.TransactionPool;
import com.android.wm.shell.shared.TransitionUtil;
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.shared.split.SplitBounds;
import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
import com.android.wm.shell.shared.split.SplitScreenConstants.SplitIndex;
@@ -2766,6 +2768,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final @WindowManager.TransitionType int type = request.getType();
final boolean isOpening = isOpeningType(type);
final boolean inFullscreen = triggerTask.getWindowingMode() == WINDOWING_MODE_FULLSCREEN;
+ final boolean inDesktopMode = DesktopModeStatus.canEnterDesktopMode(mContext)
+ && triggerTask.getWindowingMode() == WINDOWING_MODE_FREEFORM;
final StageTaskListener stage = getStageOfTask(triggerTask);
if (isOpening && inFullscreen) {
@@ -2820,6 +2824,12 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitTransitions.setDismissTransition(transition, stageType,
EXIT_REASON_FULLSCREEN_REQUEST);
}
+ } else if (isOpening && inDesktopMode) {
+ // If the app being opened is in Desktop mode, set it to full screen and dismiss
+ // split screen stage.
+ prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
+ out.setWindowingMode(triggerTask.token, WINDOWING_MODE_UNDEFINED)
+ .setBounds(triggerTask.token, null);
} else if (isOpening && inFullscreen) {
final int activityType = triggerTask.getActivityType();
if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 037b97a61b3f..bbb03e77c8c9 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -21,6 +21,7 @@ import static android.media.audio.Flags.FLAG_ENABLE_MULTICHANNEL_GROUP_DEVICE;
import static com.android.media.flags.Flags.FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER;
import static com.android.media.flags.Flags.FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES;
+import static com.android.media.flags.Flags.FLAG_ENABLE_MEDIA_ROUTE_2_INFO_PROVIDER_PACKAGE_NAME;
import static com.android.media.flags.Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2;
import static com.android.media.flags.Flags.FLAG_ENABLE_NEW_MEDIA_ROUTE_2_INFO_TYPES;
import static com.android.media.flags.Flags.FLAG_ENABLE_NEW_WIRED_MEDIA_ROUTE_2_INFO_TYPES;
@@ -631,7 +632,7 @@ public final class MediaRoute2Info implements Parcelable {
@ConnectionState
private final int mConnectionState;
private final String mClientPackageName;
- private final String mPackageName;
+ private final String mProviderPackageName;
@PlaybackVolume private final int mVolumeHandling;
private final int mVolumeMax;
private final int mVolume;
@@ -655,7 +656,7 @@ public final class MediaRoute2Info implements Parcelable {
mDescription = builder.mDescription;
mConnectionState = builder.mConnectionState;
mClientPackageName = builder.mClientPackageName;
- mPackageName = builder.mPackageName;
+ mProviderPackageName = builder.mProviderPackageName;
mVolumeHandling = builder.mVolumeHandling;
mVolumeMax = builder.mVolumeMax;
mVolume = builder.mVolume;
@@ -681,7 +682,7 @@ public final class MediaRoute2Info implements Parcelable {
mDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
mConnectionState = in.readInt();
mClientPackageName = in.readString();
- mPackageName = in.readString();
+ mProviderPackageName = in.readString();
mVolumeHandling = in.readInt();
mVolumeMax = in.readInt();
mVolume = in.readInt();
@@ -801,14 +802,19 @@ public final class MediaRoute2Info implements Parcelable {
}
/**
- * Gets the package name of the provider that published the route.
- * <p>
- * It is set by the system service.
- * @hide
+ * Gets the package name of the {@link MediaRoute2ProviderService provider} that published the
+ * route, or null if it has not yet been populated.
+ *
+ * <p>The package name of the route provider is populated by the system as part of {@link
+ * MediaRoute2ProviderService#notifyRoutes(java.util.Collection)}. As a result, it's expectable
+ * that a {@link MediaRoute2Info} instance that hasn't yet been published will have a null
+ * provider package name. Otherwise, routes obtained via {@link MediaRouter2} should have a
+ * populated provider package name.
*/
+ @FlaggedApi(FLAG_ENABLE_MEDIA_ROUTE_2_INFO_PROVIDER_PACKAGE_NAME)
@Nullable
- public String getPackageName() {
- return mPackageName;
+ public String getProviderPackageName() {
+ return mProviderPackageName;
}
/**
@@ -928,6 +934,15 @@ public final class MediaRoute2Info implements Parcelable {
}
/**
+ * Returns whether this route supports {@link #FLAG_ROUTING_TYPE_REMOTE remote routing}.
+ *
+ * @hide
+ */
+ public boolean supportsRemoteRouting() {
+ return (mRoutingTypeFlags & MediaRoute2Info.FLAG_ROUTING_TYPE_REMOTE) != 0;
+ }
+
+ /**
* Returns true if the route info has all of the required field.
* A route is valid if and only if it is obtained from
* {@link com.android.server.media.MediaRouterService}.
@@ -943,10 +958,13 @@ public final class MediaRoute2Info implements Parcelable {
/**
* Returns whether this route is visible to the package with the given name.
+ *
* @hide
*/
+ @FlaggedApi(FLAG_ENABLE_MEDIA_ROUTE_2_INFO_PROVIDER_PACKAGE_NAME)
public boolean isVisibleTo(String packageName) {
- return !mIsVisibilityRestricted || getPackageName().equals(packageName)
+ return !mIsVisibilityRestricted
+ || TextUtils.equals(getProviderPackageName(), packageName)
|| mAllowedPackages.contains(packageName);
}
@@ -1020,7 +1038,7 @@ public final class MediaRoute2Info implements Parcelable {
pw.println(indent + "mDescription=" + mDescription);
pw.println(indent + "mConnectionState=" + mConnectionState);
pw.println(indent + "mClientPackageName=" + mClientPackageName);
- pw.println(indent + "mPackageName=" + mPackageName);
+ pw.println(indent + "mProviderPackageName=" + mProviderPackageName);
dumpVolume(pw, indent);
@@ -1059,7 +1077,7 @@ public final class MediaRoute2Info implements Parcelable {
&& Objects.equals(mDescription, other.mDescription)
&& (mConnectionState == other.mConnectionState)
&& Objects.equals(mClientPackageName, other.mClientPackageName)
- && Objects.equals(mPackageName, other.mPackageName)
+ && Objects.equals(mProviderPackageName, other.mProviderPackageName)
&& (mVolumeHandling == other.mVolumeHandling)
&& (mVolumeMax == other.mVolumeMax)
&& (mVolume == other.mVolume)
@@ -1086,7 +1104,7 @@ public final class MediaRoute2Info implements Parcelable {
mDescription,
mConnectionState,
mClientPackageName,
- mPackageName,
+ mProviderPackageName,
mVolumeHandling,
mVolumeMax,
mVolume,
@@ -1162,7 +1180,7 @@ public final class MediaRoute2Info implements Parcelable {
TextUtils.writeToParcel(mDescription, dest, flags);
dest.writeInt(mConnectionState);
dest.writeString(mClientPackageName);
- dest.writeString(mPackageName);
+ dest.writeString(mProviderPackageName);
dest.writeInt(mVolumeHandling);
dest.writeInt(mVolumeMax);
dest.writeInt(mVolume);
@@ -1314,7 +1332,7 @@ public final class MediaRoute2Info implements Parcelable {
@ConnectionState
private int mConnectionState;
private String mClientPackageName;
- private String mPackageName;
+ private String mProviderPackageName;
@PlaybackVolume private int mVolumeHandling = PLAYBACK_VOLUME_FIXED;
private int mVolumeMax;
private int mVolume;
@@ -1387,7 +1405,7 @@ public final class MediaRoute2Info implements Parcelable {
mDescription = routeInfo.mDescription;
mConnectionState = routeInfo.mConnectionState;
mClientPackageName = routeInfo.mClientPackageName;
- mPackageName = routeInfo.mPackageName;
+ mProviderPackageName = routeInfo.mProviderPackageName;
mVolumeHandling = routeInfo.mVolumeHandling;
mVolumeMax = routeInfo.mVolumeMax;
mVolume = routeInfo.mVolume;
@@ -1534,11 +1552,13 @@ public final class MediaRoute2Info implements Parcelable {
/**
* Sets the package name of the route.
+ *
* @hide
*/
+ // It is set by the MediaRouterService.
@NonNull
- public Builder setPackageName(@NonNull String packageName) {
- mPackageName = packageName;
+ public Builder setProviderPackageName(@NonNull String providerPackageName) {
+ mProviderPackageName = providerPackageName;
return this;
}
diff --git a/media/java/android/media/MediaRoute2ProviderInfo.java b/media/java/android/media/MediaRoute2ProviderInfo.java
index 809ee23a2b2e..bcc8cbbc2b91 100644
--- a/media/java/android/media/MediaRoute2ProviderInfo.java
+++ b/media/java/android/media/MediaRoute2ProviderInfo.java
@@ -152,11 +152,11 @@ public final class MediaRoute2ProviderInfo implements Parcelable {
/**
* Sets the package name and unique id of the provider info.
- * <p>
- * The unique id is automatically set by
- * {@link com.android.server.media.MediaRouterService} and used to identify providers.
- * The id set by {@link MediaRoute2ProviderService} will be ignored.
- * </p>
+ *
+ * <p>The unique id is automatically set by {@link
+ * com.android.server.media.MediaRouterService} and used to identify providers. The id set
+ * by {@link MediaRoute2ProviderService} will be ignored.
+ *
* @hide
*/
@NonNull
@@ -168,10 +168,11 @@ public final class MediaRoute2ProviderInfo implements Parcelable {
final ArrayMap<String, MediaRoute2Info> newRoutes = new ArrayMap<>();
for (Map.Entry<String, MediaRoute2Info> entry : mRoutes.entrySet()) {
- MediaRoute2Info routeWithProviderId = new MediaRoute2Info.Builder(entry.getValue())
- .setPackageName(packageName)
- .setProviderId(mUniqueId)
- .build();
+ MediaRoute2Info routeWithProviderId =
+ new MediaRoute2Info.Builder(entry.getValue())
+ .setProviderPackageName(packageName)
+ .setProviderId(mUniqueId)
+ .build();
newRoutes.put(routeWithProviderId.getOriginalId(), routeWithProviderId);
}
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 3ac5de38f886..245360c925ad 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -19,6 +19,7 @@ package android.media;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import static com.android.media.flags.Flags.FLAG_ENABLE_BUILT_IN_SPEAKER_ROUTE_SUITABILITY_STATUSES;
import static com.android.media.flags.Flags.FLAG_ENABLE_GET_TRANSFERABLE_ROUTES;
+import static com.android.media.flags.Flags.FLAG_ENABLE_MEDIA_ROUTE_2_INFO_PROVIDER_PACKAGE_NAME;
import static com.android.media.flags.Flags.FLAG_ENABLE_PRIVILEGED_ROUTING_FOR_MEDIA_ROUTING_CONTROL;
import static com.android.media.flags.Flags.FLAG_ENABLE_RLP_CALLBACKS_IN_MEDIA_ROUTER2;
import static com.android.media.flags.Flags.FLAG_ENABLE_SCREEN_OFF_SCANNING;
@@ -1398,6 +1399,7 @@ public final class MediaRouter2 {
requestCreateController(controller, route, managerRequestId);
}
+ @FlaggedApi(FLAG_ENABLE_MEDIA_ROUTE_2_INFO_PROVIDER_PACKAGE_NAME)
private List<MediaRoute2Info> getSortedRoutes(
List<MediaRoute2Info> routes, List<String> packageOrder) {
if (packageOrder.isEmpty()) {
@@ -1412,11 +1414,13 @@ public final class MediaRouter2 {
ArrayList<MediaRoute2Info> sortedRoutes = new ArrayList<>(routes);
// take the negative for descending order
sortedRoutes.sort(
- Comparator.comparingInt(r -> -packagePriority.getOrDefault(r.getPackageName(), 0)));
+ Comparator.comparingInt(
+ r -> -packagePriority.getOrDefault(r.getProviderPackageName(), 0)));
return sortedRoutes;
}
@GuardedBy("mLock")
+ @FlaggedApi(FLAG_ENABLE_MEDIA_ROUTE_2_INFO_PROVIDER_PACKAGE_NAME)
private List<MediaRoute2Info> filterRoutesWithCompositePreferenceLocked(
List<MediaRoute2Info> routes) {
@@ -1429,10 +1433,10 @@ public final class MediaRouter2 {
continue;
}
if (!mDiscoveryPreference.getAllowedPackages().isEmpty()
- && (route.getPackageName() == null
+ && (route.getProviderPackageName() == null
|| !mDiscoveryPreference
.getAllowedPackages()
- .contains(route.getPackageName()))) {
+ .contains(route.getProviderPackageName()))) {
continue;
}
if (mDiscoveryPreference.shouldRemoveDuplicates()) {
@@ -3643,6 +3647,7 @@ public final class MediaRouter2 {
}
}
+ @FlaggedApi(FLAG_ENABLE_MEDIA_ROUTE_2_INFO_PROVIDER_PACKAGE_NAME)
@Override
public List<MediaRoute2Info> filterRoutesWithIndividualPreference(
List<MediaRoute2Info> routes, RouteDiscoveryPreference discoveryPreference) {
@@ -3652,10 +3657,10 @@ public final class MediaRouter2 {
continue;
}
if (!discoveryPreference.getAllowedPackages().isEmpty()
- && (route.getPackageName() == null
+ && (route.getProviderPackageName() == null
|| !discoveryPreference
.getAllowedPackages()
- .contains(route.getPackageName()))) {
+ .contains(route.getProviderPackageName()))) {
continue;
}
filteredRoutes.add(route);
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 7e1dccf2d366..3854747f46e0 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -20,9 +20,11 @@ import static android.media.MediaRouter2.SCANNING_STATE_NOT_SCANNING;
import static android.media.MediaRouter2.SCANNING_STATE_WHILE_INTERACTIVE;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+import static com.android.media.flags.Flags.FLAG_ENABLE_MEDIA_ROUTE_2_INFO_PROVIDER_PACKAGE_NAME;
import android.Manifest;
import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -285,6 +287,7 @@ public final class MediaRouter2Manager {
(route) -> sessionInfo.isSystemSession() ^ route.isSystemRoute());
}
+ @FlaggedApi(FLAG_ENABLE_MEDIA_ROUTE_2_INFO_PROVIDER_PACKAGE_NAME)
private List<MediaRoute2Info> getSortedRoutes(RouteDiscoveryPreference preference) {
if (!preference.shouldRemoveDuplicates()) {
synchronized (mRoutesLock) {
@@ -302,12 +305,15 @@ public final class MediaRouter2Manager {
routes = new ArrayList<>(mRoutes.values());
}
// take the negative for descending order
- routes.sort(Comparator.comparingInt(
- r -> -packagePriority.getOrDefault(r.getPackageName(), 0)));
+ routes.sort(
+ Comparator.comparingInt(
+ r -> -packagePriority.getOrDefault(r.getProviderPackageName(), 0)));
return routes;
}
- private List<MediaRoute2Info> getFilteredRoutes(@NonNull RoutingSessionInfo sessionInfo,
+ @FlaggedApi(FLAG_ENABLE_MEDIA_ROUTE_2_INFO_PROVIDER_PACKAGE_NAME)
+ private List<MediaRoute2Info> getFilteredRoutes(
+ @NonNull RoutingSessionInfo sessionInfo,
boolean includeSelectedRoutes,
@Nullable Predicate<MediaRoute2Info> additionalFilter) {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
@@ -336,9 +342,10 @@ public final class MediaRouter2Manager {
continue;
}
if (!discoveryPreference.getAllowedPackages().isEmpty()
- && (route.getPackageName() == null
- || !discoveryPreference.getAllowedPackages()
- .contains(route.getPackageName()))) {
+ && (route.getProviderPackageName() == null
+ || !discoveryPreference
+ .getAllowedPackages()
+ .contains(route.getProviderPackageName()))) {
continue;
}
if (additionalFilter != null && !additionalFilter.test(route)) {
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
index bbe8e4ed7b34..4398b261377b 100644
--- a/media/java/android/media/flags/media_better_together.aconfig
+++ b/media/java/android/media/flags/media_better_together.aconfig
@@ -60,6 +60,13 @@ flag {
}
flag {
+ name: "enable_media_route_2_info_provider_package_name"
+ namespace: "media_better_together"
+ description: "Enables a new API to obtain the provider package name from MediaRoute2Info."
+ bug: "378788958"
+}
+
+flag {
name: "enable_mirroring_in_media_router_2"
namespace: "media_better_together"
description: "Enables support for mirroring routes in the MediaRouter2 framework, allowing Output Switcher to offer mirroring routes."
diff --git a/native/android/dynamic_instrumentation_manager.cpp b/native/android/dynamic_instrumentation_manager.cpp
index 074973188c66..ee2cd6f3fcde 100644
--- a/native/android/dynamic_instrumentation_manager.cpp
+++ b/native/android/dynamic_instrumentation_manager.cpp
@@ -73,6 +73,7 @@ ADynamicInstrumentationManager_TargetProcess* ADynamicInstrumentationManager_Tar
void ADynamicInstrumentationManager_TargetProcess_destroy(
const ADynamicInstrumentationManager_TargetProcess* instance) {
+ if (instance == nullptr) return;
delete instance;
}
@@ -104,6 +105,7 @@ ADynamicInstrumentationManager_MethodDescriptor_create(const char* fullyQualifie
void ADynamicInstrumentationManager_MethodDescriptor_destroy(
const ADynamicInstrumentationManager_MethodDescriptor* instance) {
+ if (instance == nullptr) return;
delete instance;
}
@@ -135,6 +137,7 @@ uint64_t ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOff
void ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy(
const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
+ if (instance == nullptr) return;
delete instance;
}
diff --git a/native/android/include_platform/android/dynamic_instrumentation_manager.h b/native/android/include_platform/android/dynamic_instrumentation_manager.h
index ab9f37034a22..7bb7615bc3a1 100644
--- a/native/android/include_platform/android/dynamic_instrumentation_manager.h
+++ b/native/android/include_platform/android/dynamic_instrumentation_manager.h
@@ -40,9 +40,12 @@ typedef struct ADynamicInstrumentationManager_ExecutableMethodFileOffsets
*
* @param uid of targeted process.
* @param pid of targeted process.
- * @param processName to disambiguate from corner cases that may arise from pid reuse.
+ * @param processName UTF-8 encoded string representing the same process as specified by `pid`.
+ * Supplied to disambiguate from corner cases that may arise from pid reuse.
+ * Referenced parameter must outlive the returned
+ * ADynamicInstrumentationManager_TargetProcess.
*/
-ADynamicInstrumentationManager_TargetProcess* _Nonnull
+ADynamicInstrumentationManager_TargetProcess* _Nullable
ADynamicInstrumentationManager_TargetProcess_create(
uid_t uid, pid_t pid, const char* _Nonnull processName) __INTRODUCED_IN(36);
/**
@@ -51,22 +54,27 @@ ADynamicInstrumentationManager_TargetProcess* _Nonnull
* @param instance returned from ADynamicInstrumentationManager_TargetProcess_create.
*/
void ADynamicInstrumentationManager_TargetProcess_destroy(
- const ADynamicInstrumentationManager_TargetProcess* _Nonnull instance) __INTRODUCED_IN(36);
+ const ADynamicInstrumentationManager_TargetProcess* _Nullable instance) __INTRODUCED_IN(36);
/**
* Initializes an ADynamicInstrumentationManager_MethodDescriptor. Caller must clean up when they
- * are done with ADynamicInstrumentationManager_MethodDescriptor_Destroy.
+ * are done with ADynamicInstrumentationManager_MethodDescriptor_destroy.
*
- * @param fullyQualifiedClassName fqcn of class containing the method.
- * @param methodName
- * @param fullyQualifiedParameters fqcn of parameters of the method's signature, or e.g. "int" for
- * primitives.
+ * @param fullyQualifiedClassName UTF-8 encoded fqcn of class containing the method. Referenced
+ * parameter must outlive the returned
+ * ADynamicInstrumentationManager_MethodDescriptor.
+ * @param methodName UTF-8 encoded method name. Referenced parameter must outlive the returned
+ * ADynamicInstrumentationManager_MethodDescriptor.
+ * @param fullyQualifiedParameters UTF-8 encoded fqcn of parameters of the method's signature,
+ * or e.g. "int" for primitives. Referenced parameter should
+ * outlive the returned
+ * ADynamicInstrumentationManager_MethodDescriptor.
* @param numParameters length of `fullyQualifiedParameters` array.
*/
-ADynamicInstrumentationManager_MethodDescriptor* _Nonnull
+ADynamicInstrumentationManager_MethodDescriptor* _Nullable
ADynamicInstrumentationManager_MethodDescriptor_create(
const char* _Nonnull fullyQualifiedClassName, const char* _Nonnull methodName,
- const char* _Nonnull fullyQualifiedParameters[_Nonnull], size_t numParameters)
+ const char* _Nonnull* _Nonnull fullyQualifiedParameters, size_t numParameters)
__INTRODUCED_IN(36);
/**
* Clean up an ADynamicInstrumentationManager_MethodDescriptor.
@@ -74,14 +82,16 @@ ADynamicInstrumentationManager_MethodDescriptor* _Nonnull
* @param instance returned from ADynamicInstrumentationManager_MethodDescriptor_create.
*/
void ADynamicInstrumentationManager_MethodDescriptor_destroy(
- const ADynamicInstrumentationManager_MethodDescriptor* _Nonnull instance)
+ const ADynamicInstrumentationManager_MethodDescriptor* _Nullable instance)
__INTRODUCED_IN(36);
/**
* Get the containerPath calculated by
* ADynamicInstrumentationManager_getExecutableMethodFileOffsets.
* @param instance created with ADynamicInstrumentationManager_getExecutableMethodFileOffsets.
- * @return The OS path of the containing file.
+ * @return The OS path of the containing file as a UTF-8 string, which has the same lifetime
+ * as the ADynamicInstrumentationManager_ExecutableMethodFileOffsets instance passed
+ * as a param.
*/
const char* _Nullable ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerPath(
const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
@@ -90,7 +100,8 @@ const char* _Nullable ADynamicInstrumentationManager_ExecutableMethodFileOffsets
* Get the containerOffset calculated by
* ADynamicInstrumentationManager_getExecutableMethodFileOffsets.
* @param instance created with ADynamicInstrumentationManager_getExecutableMethodFileOffsets.
- * @return The offset of the containing file within the process' memory.
+ * @return The absolute address of the containing file within remote the process' virtual memory
+ * space.
*/
uint64_t ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerOffset(
const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
@@ -98,7 +109,8 @@ uint64_t ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainer
/**
* Get the methodOffset calculated by ADynamicInstrumentationManager_getExecutableMethodFileOffsets.
* @param instance created with ADynamicInstrumentationManager_getExecutableMethodFileOffsets.
- * @return The offset of the method within the containing file.
+ * @return The offset of the method within the container whose address is returned by
+ * ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerOffset.
*/
uint64_t ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOffset(
const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
@@ -109,7 +121,7 @@ uint64_t ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOff
* @param instance returned from ADynamicInstrumentationManager_getExecutableMethodFileOffsets.
*/
void ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy(
- const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
+ const ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nullable instance)
__INTRODUCED_IN(36);
/**
* Provides ART metadata about the described java method within the target process.
@@ -118,7 +130,9 @@ void ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy(
* @param methodDescriptor describes the targeted method.
* @param out will be populated with the data if successful. A nullptr combined
* with an OK status means that the program method is defined, but the offset
- * info was unavailable because it is not AOT compiled.
+ * info was unavailable because it is not AOT compiled. Caller owns `out` and
+ * should clean it up with
+ * ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy.
* @return status indicating success or failure. The values correspond to the `binder_exception_t`
* enum values from <android/binder_status.h>.
*/
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index 9257901bcd1f..0db99ffd208a 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -22,7 +22,6 @@
#include <aidl/android/hardware/power/SessionHint.h>
#include <aidl/android/hardware/power/SessionMode.h>
#include <aidl/android/hardware/power/SessionTag.h>
-#include <aidl/android/hardware/power/SupportInfo.h>
#include <aidl/android/hardware/power/WorkDuration.h>
#include <aidl/android/hardware/power/WorkDurationFixedV1.h>
#include <aidl/android/os/IHintManager.h>
@@ -149,36 +148,10 @@ private:
std::future<bool> mChannelCreationFinished;
};
-class SupportInfoWrapper {
-public:
- SupportInfoWrapper(hal::SupportInfo& info);
- bool isSessionModeSupported(hal::SessionMode mode);
- bool isSessionHintSupported(hal::SessionHint hint);
-
-private:
- template <class T>
- bool getEnumSupportFromBitfield(T& enumValue, int64_t& supportBitfield) {
- // extract the bit corresponding to the enum by shifting the bitfield
- // over that much and cutting off any extra values
- return (supportBitfield >> static_cast<int>(enumValue)) % 2;
- }
- hal::SupportInfo mSupportInfo;
-};
-
-class HintManagerClient : public IHintManager::BnHintManagerClient {
-public:
- // Currently a no-op that exists for FMQ init to call in the future
- ndk::ScopedAStatus receiveChannelConfig(const hal::ChannelConfig&) {
- return ndk::ScopedAStatus::ok();
- }
-};
-
struct APerformanceHintManager {
public:
static APerformanceHintManager* getInstance();
- APerformanceHintManager(std::shared_ptr<IHintManager>& service,
- IHintManager::HintManagerClientData&& clientData,
- std::shared_ptr<HintManagerClient> callbackClient);
+ APerformanceHintManager(std::shared_ptr<IHintManager>& service, int64_t preferredRateNanos);
APerformanceHintManager() = delete;
~APerformanceHintManager();
@@ -196,21 +169,29 @@ public:
FMQWrapper& getFMQWrapper();
bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex);
void initJava(JNIEnv* _Nonnull env);
+ ndk::ScopedAIBinder_Weak x;
template <class T>
static void layersFromNativeSurfaces(ANativeWindow** windows, int numWindows,
ASurfaceControl** controls, int numSurfaceControls,
std::vector<T>& out);
- ndk::SpAIBinder& getToken();
- SupportInfoWrapper& getSupportInfo();
private:
+ // Necessary to create an empty binder object
+ static void* tokenStubOnCreate(void*) {
+ return nullptr;
+ }
+ static void tokenStubOnDestroy(void*) {}
+ static binder_status_t tokenStubOnTransact(AIBinder*, transaction_code_t, const AParcel*,
+ AParcel*) {
+ return STATUS_OK;
+ }
+
static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager);
std::shared_ptr<IHintManager> mHintManager;
- std::shared_ptr<HintManagerClient> mCallbackClient;
- IHintManager::HintManagerClientData mClientData;
- SupportInfoWrapper mSupportInfoWrapper;
ndk::SpAIBinder mToken;
+ const int64_t mPreferredRateNanos;
+ std::optional<int32_t> mMaxGraphicsPipelineThreadsCount;
FMQWrapper mFMQWrapper;
double mHintBudget = kMaxLoadHintsPerInterval;
int64_t mLastBudgetReplenish = 0;
@@ -292,27 +273,14 @@ static FMQWrapper& getFMQ() {
return APerformanceHintManager::getInstance()->getFMQWrapper();
}
-// ===================================== SupportInfoWrapper implementation
-
-SupportInfoWrapper::SupportInfoWrapper(hal::SupportInfo& info) : mSupportInfo(info) {}
-
-bool SupportInfoWrapper::isSessionHintSupported(hal::SessionHint hint) {
- return getEnumSupportFromBitfield(hint, mSupportInfo.sessionHints);
-}
-
-bool SupportInfoWrapper::isSessionModeSupported(hal::SessionMode mode) {
- return getEnumSupportFromBitfield(mode, mSupportInfo.sessionModes);
-}
-
// ===================================== APerformanceHintManager implementation
APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager>& manager,
- IHintManager::HintManagerClientData&& clientData,
- std::shared_ptr<HintManagerClient> callbackClient)
- : mHintManager(std::move(manager)),
- mCallbackClient(callbackClient),
- mClientData(clientData),
- mSupportInfoWrapper(clientData.supportInfo),
- mToken(callbackClient->asBinder()) {
+ int64_t preferredRateNanos)
+ : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {
+ static AIBinder_Class* tokenBinderClass =
+ AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy,
+ tokenStubOnTransact);
+ mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr));
if (mFMQWrapper.isSupported()) {
mFMQWrapper.setToken(mToken);
mFMQWrapper.startChannel(mHintManager.get());
@@ -347,17 +315,16 @@ APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintMa
ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
return nullptr;
}
- std::shared_ptr<HintManagerClient> client = ndk::SharedRefBase::make<HintManagerClient>();
- IHintManager::HintManagerClientData clientData;
- ndk::ScopedAStatus ret = manager->registerClient(client, &clientData);
+ int64_t preferredRateNanos = -1L;
+ ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
if (!ret.isOk()) {
- ALOGE("%s: PerformanceHint is not supported. %s", __FUNCTION__, ret.getMessage());
+ ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage());
return nullptr;
}
- if (clientData.preferredRateNanos <= 0) {
- clientData.preferredRateNanos = -1L;
+ if (preferredRateNanos <= 0) {
+ preferredRateNanos = -1L;
}
- return new APerformanceHintManager(manager, std::move(clientData), client);
+ return new APerformanceHintManager(manager, preferredRateNanos);
}
bool APerformanceHintManager::canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) {
@@ -422,9 +389,7 @@ APerformanceHintSession* APerformanceHintManager::createSessionUsingConfig(
ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage());
return nullptr;
}
-
- auto out = new APerformanceHintSession(mHintManager, std::move(session),
- mClientData.preferredRateNanos,
+ auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
sessionCreationConfig->targetWorkDurationNanos, isJava,
sessionConfig.id == -1
? std::nullopt
@@ -451,11 +416,24 @@ APerformanceHintSession* APerformanceHintManager::getSessionFromJava(JNIEnv* env
}
int64_t APerformanceHintManager::getPreferredRateNanos() const {
- return mClientData.preferredRateNanos;
+ return mPreferredRateNanos;
}
int32_t APerformanceHintManager::getMaxGraphicsPipelineThreadsCount() {
- return mClientData.maxGraphicsPipelineThreads;
+ if (!mMaxGraphicsPipelineThreadsCount.has_value()) {
+ int32_t threadsCount = -1;
+ ndk::ScopedAStatus ret = mHintManager->getMaxGraphicsPipelineThreadsCount(&threadsCount);
+ if (!ret.isOk()) {
+ ALOGE("%s: PerformanceHint cannot get max graphics pipeline threads count. %s",
+ __FUNCTION__, ret.getMessage());
+ return -1;
+ }
+ if (threadsCount <= 0) {
+ threadsCount = -1;
+ }
+ mMaxGraphicsPipelineThreadsCount.emplace(threadsCount);
+ }
+ return mMaxGraphicsPipelineThreadsCount.value();
}
FMQWrapper& APerformanceHintManager::getFMQWrapper() {
@@ -472,14 +450,6 @@ void APerformanceHintManager::initJava(JNIEnv* _Nonnull env) {
mJavaInitialized = true;
}
-ndk::SpAIBinder& APerformanceHintManager::getToken() {
- return mToken;
-}
-
-SupportInfoWrapper& APerformanceHintManager::getSupportInfo() {
- return mSupportInfoWrapper;
-}
-
// ===================================== APerformanceHintSession implementation
constexpr int kNumEnums = enum_size<hal::SessionHint>();
diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
index e3c10f63abb4..c166e738ffb2 100644
--- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
+++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
@@ -56,6 +56,9 @@ public:
const SessionCreationConfig& creationConfig, hal::SessionConfig* config,
std::shared_ptr<IHintSession>* _aidl_return),
(override));
+ MOCK_METHOD(ScopedAStatus, getHintSessionPreferredRate, (int64_t * _aidl_return), (override));
+ MOCK_METHOD(ScopedAStatus, getMaxGraphicsPipelineThreadsCount, (int32_t* _aidl_return),
+ (override));
MOCK_METHOD(ScopedAStatus, setHintSessionThreads,
(const std::shared_ptr<IHintSession>& hintSession,
const ::std::vector<int32_t>& tids),
@@ -81,11 +84,6 @@ public:
MOCK_METHOD(ScopedAStatus, getGpuHeadroomMinIntervalMillis, (int64_t* _aidl_return),
(override));
MOCK_METHOD(ScopedAStatus, passSessionManagerBinder, (const SpAIBinder& sessionManager));
- MOCK_METHOD(ScopedAStatus, registerClient,
- (const std::shared_ptr<::aidl::android::os::IHintManager::IHintManagerClient>&
- clientDataIn,
- ::aidl::android::os::IHintManager::HintManagerClientData* _aidl_return),
- (override));
MOCK_METHOD(SpAIBinder, asBinder, (), (override));
MOCK_METHOD(bool, isRemote, (), (override));
};
@@ -127,9 +125,10 @@ public:
APerformanceHintManager* createManager() {
APerformanceHint_setUseFMQForTesting(mUsingFMQ);
- ON_CALL(*mMockIHintManager, registerClient(_, _))
- .WillByDefault(
- DoAll(SetArgPointee<1>(mClientData), [] { return ScopedAStatus::ok(); }));
+ ON_CALL(*mMockIHintManager, getHintSessionPreferredRate(_))
+ .WillByDefault(DoAll(SetArgPointee<0>(123L), [] { return ScopedAStatus::ok(); }));
+ ON_CALL(*mMockIHintManager, getMaxGraphicsPipelineThreadsCount(_))
+ .WillByDefault(DoAll(SetArgPointee<0>(5), [] { return ScopedAStatus::ok(); }));
return APerformanceHint_getManager();
}
@@ -239,20 +238,6 @@ public:
int kMockQueueSize = 20;
bool mUsingFMQ = false;
- IHintManager::HintManagerClientData mClientData{
- .powerHalVersion = 6,
- .maxGraphicsPipelineThreads = 5,
- .preferredRateNanos = 123L,
- .supportInfo{
- .usesSessions = true,
- .boosts = 0,
- .modes = 0,
- .sessionHints = -1,
- .sessionModes = -1,
- .sessionTags = -1,
- },
- };
-
int32_t mMaxLoadHintsPerInterval;
int64_t mLoadHintInterval;
@@ -271,6 +256,12 @@ bool equalsWithoutTimestamp(hal::WorkDuration lhs, hal::WorkDuration rhs) {
lhs.gpuDurationNanos == rhs.gpuDurationNanos && lhs.durationNanos == rhs.durationNanos;
}
+TEST_F(PerformanceHintTest, TestGetPreferredUpdateRateNanos) {
+ APerformanceHintManager* manager = createManager();
+ int64_t preferredUpdateRateNanos = APerformanceHint_getPreferredUpdateRateNanos(manager);
+ EXPECT_EQ(123L, preferredUpdateRateNanos);
+}
+
TEST_F(PerformanceHintTest, TestSession) {
APerformanceHintManager* manager = createManager();
APerformanceHintSession* session = createSession(manager);
diff --git a/nfc/Android.bp b/nfc/Android.bp
index b82dec88993d..c33665aef41d 100644
--- a/nfc/Android.bp
+++ b/nfc/Android.bp
@@ -56,7 +56,7 @@ java_sdk_library {
],
defaults: ["framework-module-defaults"],
sdk_version: "module_current",
- min_sdk_version: "current",
+ min_sdk_version: "35", // Make it 36 once available.
installable: true,
optimize: {
enabled: false,
diff --git a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/SettingsSpinnerPreference.java b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/SettingsSpinnerPreference.java
index 63fe1b509751..e173c5e996df 100644
--- a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/SettingsSpinnerPreference.java
+++ b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/SettingsSpinnerPreference.java
@@ -25,13 +25,15 @@ import android.widget.Spinner;
import androidx.preference.Preference;
import androidx.preference.Preference.OnPreferenceClickListener;
import androidx.preference.PreferenceViewHolder;
+
import com.android.settingslib.widget.spinner.R;
/**
* This preference uses Spinner & SettingsSpinnerAdapter which provide default layouts for
* both view and drop down view of the Spinner.
*/
-public class SettingsSpinnerPreference extends Preference implements OnPreferenceClickListener {
+public class SettingsSpinnerPreference extends Preference
+ implements OnPreferenceClickListener, GroupSectionDividerMixin {
private SettingsSpinnerAdapter mAdapter;
private AdapterView.OnItemSelectedListener mListener;
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 5a4d3ce5661b..63c8929ef652 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -667,4 +667,25 @@
<item>3</item>
</string-array>
+ <!-- Options for showing shade on external display for developers -->
+ <string-array name="shade_display_awareness_entries" >
+ <item>Device display only (Default)</item>
+ <item>External display</item>
+ <item>Focus-based</item>
+ </string-array>
+
+ <!-- Options for showing shade on external display for developers -->
+ <string-array name="shade_display_awareness_summaries" >
+ <item>Show shade on device display only </item>
+ <item>Show device on single external display</item>
+ <item>Show device on last focused display</item>
+ </string-array>
+
+ <!-- Values for showing shade on external display for developers -->
+ <string-array name="shade_display_awareness_values" >
+ <item>device-display</item>
+ <item>external-display</item>
+ <item>focus-based</item>
+ </string-array>
+
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index eaf155df4785..e1929b725a58 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -990,6 +990,9 @@
<!-- UI debug setting: simulate secondary display devices using overlays [CHAR LIMIT=45] -->
<string name="overlay_display_devices_title">Simulate secondary displays</string>
+ <!-- UI debug setting: shade display awareness title [CHAR LIMIT=45] -->
+ <string name="shade_display_awareness_title">Shade display position</string>
+
<!-- Preference category for application debugging development settings. [CHAR LIMIT=25] -->
<string name="debug_applications_category">Apps</string>
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 9004488c2e12..c88a7fd834d6 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -182,6 +182,7 @@ public class SettingsBackupTest {
Settings.Global.DEVELOPMENT_FORCE_RTL,
Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR,
+ Settings.Global.DEVELOPMENT_SHADE_DISPLAY_AWARENESS,
Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH,
Settings.Global.DEVICE_DEMO_MODE,
Settings.Global.DEVICE_IDLE_CONSTANTS,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
index 85f549d43a11..55b42931b1fa 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
@@ -19,6 +19,7 @@ package com.android.systemui.bouncer.ui.composable
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.overscroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
@@ -101,6 +102,7 @@ private fun SceneScope.BouncerScene(
viewModel,
dialogFactory,
Modifier.element(Bouncer.Elements.Content)
+ .overscroll(verticalOverscrollEffect)
.sysuiResTag(Bouncer.TestTags.Root)
.fillMaxSize(),
)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt
index 364adcaffd77..5e9ade163ac2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt
@@ -82,20 +82,15 @@ constructor(
Modifier.shortcutPadding()
} else {
Modifier
- }
+ },
)
}
}
}
@Composable
- fun SceneScope.IndicationArea(
- modifier: Modifier = Modifier,
- ) {
- Element(
- key = IndicationAreaElementKey,
- modifier = modifier.indicationAreaPadding(),
- ) {
+ fun SceneScope.IndicationArea(modifier: Modifier = Modifier) {
+ Element(key = IndicationAreaElementKey, modifier = modifier.indicationAreaPadding()) {
content {
IndicationArea(
indicationAreaViewModel = indicationAreaViewModel,
@@ -138,24 +133,20 @@ constructor(
ResourcesCompat.getDrawable(
context.resources,
R.drawable.keyguard_bottom_affordance_bg,
- context.theme
+ context.theme,
)
foreground =
ResourcesCompat.getDrawable(
context.resources,
R.drawable.keyguard_bottom_affordance_selected_border,
- context.theme
+ context.theme,
)
visibility = View.INVISIBLE
setPadding(padding, padding, padding, padding)
}
setBinding(
- binder.bind(
- view,
- viewModel,
- transitionAlpha,
- ) {
+ binder.bind(view, viewModel, transitionAlpha) {
indicationController.showTransientIndication(it)
}
)
@@ -164,10 +155,7 @@ constructor(
},
onRelease = { binding?.destroy() },
modifier =
- modifier.size(
- width = shortcutSizeDp().width,
- height = shortcutSizeDp().height,
- )
+ modifier.size(width = shortcutSizeDp().width, height = shortcutSizeDp().height),
)
}
@@ -182,6 +170,8 @@ constructor(
AndroidView(
factory = { context ->
val view = KeyguardIndicationArea(context, null)
+ view.isFocusable = true
+ view.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES
setDisposable(
KeyguardIndicationAreaBinder.bind(
view = view,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationLockscreenScrim.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationLockscreenScrim.kt
index 48067ce3c4a0..ef8911dae566 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationLockscreenScrim.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationLockscreenScrim.kt
@@ -29,7 +29,7 @@ import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.shared.model.ShadeMode
@@ -42,7 +42,7 @@ import kotlinx.coroutines.launch
* transition.
*/
@Composable
-fun SceneScope.NotificationLockscreenScrim(
+fun ContentScope.NotificationLockscreenScrim(
viewModel: NotificationLockscreenScrimViewModel,
modifier: Modifier = Modifier,
) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationScrimNestedScrollConnection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationScrimNestedScrollConnection.kt
index 94c18cdbef5a..cb87f0e7cf1c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationScrimNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationScrimNestedScrollConnection.kt
@@ -62,7 +62,6 @@ fun NotificationScrimNestedScrollConnection(
canStartPostScroll = { offsetAvailable, _, _ ->
offsetAvailable > 0 && (scrimOffset() < maxScrimOffset || isCurrentGestureOverscroll())
},
- canStartPostFling = { false },
onStart = { firstScroll ->
onStart(firstScroll)
object : ScrollController {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackNestedScrollConnection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackNestedScrollConnection.kt
index d8abfd7a4b94..e1ee59ba0626 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackNestedScrollConnection.kt
@@ -25,11 +25,13 @@ import androidx.compose.foundation.layout.offset
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastCoerceAtLeast
import com.android.compose.nestedscroll.OnStopScope
@@ -80,9 +82,29 @@ fun Modifier.stackVerticalOverscroll(
}
return this.then(
- Modifier.nestedScroll(stackNestedScrollConnection).offset {
- IntOffset(x = 0, y = overscrollOffset.value.roundToInt())
- }
+ Modifier.nestedScroll(
+ remember {
+ object : NestedScrollConnection {
+ override suspend fun onPostFling(
+ consumed: Velocity,
+ available: Velocity,
+ ): Velocity {
+ return if (available.y < 0f && !canScrollForward()) {
+ overscrollOffset.animateTo(
+ targetValue = 0f,
+ initialVelocity = available.y,
+ animationSpec = tween(),
+ )
+ available
+ } else {
+ Velocity.Zero
+ }
+ }
+ }
+ }
+ )
+ .nestedScroll(stackNestedScrollConnection)
+ .offset { IntOffset(x = 0, y = overscrollOffset.value.roundToInt()) }
)
}
@@ -100,7 +122,6 @@ fun NotificationStackNestedScrollConnection(
canStartPostScroll = { offsetAvailable, offsetBeforeStart, _ ->
offsetAvailable < 0f && offsetBeforeStart < 0f && !canScrollForward()
},
- canStartPostFling = { velocityAvailable -> velocityAvailable < 0f && !canScrollForward() },
onStart = { firstScroll ->
onStart(firstScroll)
object : ScrollController {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
index ae273d8e2ad9..b54de784a202 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
@@ -45,6 +45,7 @@ import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.windowInsetsBottomHeight
+import androidx.compose.foundation.overscroll
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
@@ -84,10 +85,10 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.lerp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ContentKey
+import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.LowestZIndexContentPicker
import com.android.compose.animation.scene.NestedScrollBehavior
-import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.SceneTransitionLayoutState
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.modifiers.thenIf
@@ -134,7 +135,7 @@ private val quickSettingsShadeContentKey: ContentKey
* entire size of the scene.
*/
@Composable
-fun SceneScope.HeadsUpNotificationSpace(
+fun ContentScope.HeadsUpNotificationSpace(
stackScrollView: NotificationScrollView,
viewModel: NotificationsPlaceholderViewModel,
useHunBounds: () -> Boolean = { true },
@@ -176,7 +177,7 @@ fun SceneScope.HeadsUpNotificationSpace(
* the user. When swiped up, the heads up notification is snoozed.
*/
@Composable
-fun SceneScope.SnoozeableHeadsUpNotificationSpace(
+fun ContentScope.SnoozeableHeadsUpNotificationSpace(
stackScrollView: NotificationScrollView,
viewModel: NotificationsPlaceholderViewModel,
) {
@@ -246,7 +247,7 @@ fun SceneScope.SnoozeableHeadsUpNotificationSpace(
/** Adds the space where notification stack should appear in the scene. */
@Composable
-fun SceneScope.ConstrainedNotificationStack(
+fun ContentScope.ConstrainedNotificationStack(
stackScrollView: NotificationScrollView,
viewModel: NotificationsPlaceholderViewModel,
modifier: Modifier = Modifier,
@@ -281,7 +282,7 @@ fun SceneScope.ConstrainedNotificationStack(
*/
@OptIn(ExperimentalLayoutApi::class)
@Composable
-fun SceneScope.NotificationScrollingStack(
+fun ContentScope.NotificationScrollingStack(
shadeSession: SaveableSession,
stackScrollView: NotificationScrollView,
viewModel: NotificationsPlaceholderViewModel,
@@ -480,6 +481,7 @@ fun SceneScope.NotificationScrollingStack(
modifier =
modifier
.element(Notifications.Elements.NotificationScrim)
+ .overscroll(verticalOverscrollEffect)
.offset {
// if scrim is expanded while transitioning to Gone or QS scene, increase the
// offset in step with the corresponding transition so that it is 0 when it
@@ -622,7 +624,7 @@ fun SceneScope.NotificationScrollingStack(
* the notification contents (stack, footer, shelf) should be drawn.
*/
@Composable
-fun SceneScope.NotificationStackCutoffGuideline(
+fun ContentScope.NotificationStackCutoffGuideline(
stackScrollView: NotificationScrollView,
viewModel: NotificationsPlaceholderViewModel,
modifier: Modifier = Modifier,
@@ -642,7 +644,7 @@ fun SceneScope.NotificationStackCutoffGuideline(
}
@Composable
-private fun SceneScope.NotificationPlaceholder(
+private fun ContentScope.NotificationPlaceholder(
stackScrollView: NotificationScrollView,
viewModel: NotificationsPlaceholderViewModel,
useStackBounds: () -> Boolean,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
index 5fb9416cf35b..e4f4df386583 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
@@ -37,6 +37,7 @@ import com.android.systemui.notifications.ui.composable.SnoozeableHeadsUpNotific
import com.android.systemui.qs.ui.composable.QuickSettings
import com.android.systemui.qs.ui.composable.QuickSettings.SharedValues.MediaLandscapeTopOffset
import com.android.systemui.qs.ui.composable.QuickSettings.SharedValues.MediaOffset.Default
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.viewmodel.GoneUserActionsViewModel
import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView
@@ -70,18 +71,22 @@ constructor(
@Composable
override fun SceneScope.Content(modifier: Modifier) {
- val isIdle by remember {
- derivedStateOf { layoutState.transitionState is TransitionState.Idle }
+ val isIdleAndNotOccluded by remember {
+ derivedStateOf {
+ layoutState.transitionState is TransitionState.Idle &&
+ Overlays.NotificationsShade !in layoutState.transitionState.currentOverlays
+ }
}
- LaunchedEffect(isIdle) {
+ LaunchedEffect(isIdleAndNotOccluded) {
// Wait for being Idle on this Scene, otherwise LaunchedEffect would fire too soon,
// and another transition could override the NSSL stack bounds.
- if (isIdle) {
+ if (isIdleAndNotOccluded) {
// Reset the stack bounds to avoid caching these values from the previous Scenes,
// and not to confuse the StackScrollAlgorithm when it displays a HUN over GONE.
notificationStackScrolLView.get().apply {
- setStackTop(0f)
+ // use -headsUpInset to allow HUN translation outside bounds for snoozing
+ setStackTop(-getHeadsUpInset().toFloat())
setStackCutoff(0f)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
index 9de7a5d659ae..55fafd5cfeca 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
@@ -33,7 +33,6 @@ import com.android.systemui.scene.ui.composable.transitions.notificationsShadeTo
import com.android.systemui.scene.ui.composable.transitions.shadeToQuickSettingsTransition
import com.android.systemui.scene.ui.composable.transitions.toNotificationsShadeTransition
import com.android.systemui.scene.ui.composable.transitions.toQuickSettingsShadeTransition
-import com.android.systemui.shade.ui.composable.OverlayShade
import com.android.systemui.shade.ui.composable.Shade
/**
@@ -134,27 +133,11 @@ val SceneContainerTransitions = transitions {
}
// Scene overscroll
-
+ // TODO(b/382477212) Remove STL Overscroll DSL
overscrollDisabled(Scenes.Gone, Orientation.Vertical)
overscrollDisabled(Scenes.Lockscreen, Orientation.Vertical)
- overscroll(Scenes.Bouncer, Orientation.Vertical) {
- translate(Bouncer.Elements.Content, y = { absoluteDistance })
- }
- overscroll(Scenes.Shade, Orientation.Vertical) {
- translate(
- Notifications.Elements.NotificationScrim,
- y = Shade.Dimensions.ScrimOverscrollLimit,
- )
- translate(Shade.Elements.SplitShadeStartColumn, y = Shade.Dimensions.ScrimOverscrollLimit)
- translate(
- Notifications.Elements.NotificationStackPlaceholder,
- y = Shade.Dimensions.ScrimOverscrollLimit,
- )
- }
- overscroll(Overlays.NotificationsShade, Orientation.Vertical) {
- translate(OverlayShade.Elements.Panel, y = OverlayShade.Dimensions.OverscrollLimit)
- }
- overscroll(Overlays.QuickSettingsShade, Orientation.Vertical) {
- translate(OverlayShade.Elements.Panel, y = OverlayShade.Dimensions.OverscrollLimit)
- }
+ overscrollDisabled(Scenes.Bouncer, Orientation.Vertical)
+ overscrollDisabled(Scenes.Shade, Orientation.Vertical)
+ overscrollDisabled(Overlays.NotificationsShade, Orientation.Vertical)
+ overscrollDisabled(Overlays.QuickSettingsShade, Orientation.Vertical)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
index 46f5ecd99301..8a5c96da5ac6 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
@@ -35,6 +35,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBarsIgnoringVisibility
import androidx.compose.foundation.layout.waterfall
import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.overscroll
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
@@ -65,7 +66,10 @@ fun SceneScope.OverlayShade(
Box(modifier = Modifier.fillMaxSize().panelPadding(), contentAlignment = Alignment.TopEnd) {
Panel(
- modifier = Modifier.element(OverlayShade.Elements.Panel).panelSize(),
+ modifier =
+ Modifier.element(OverlayShade.Elements.Panel)
+ .overscroll(verticalOverscrollEffect)
+ .panelSize(),
content = content,
)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index 22b6dbcf41ec..79fd1d7ddd8f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -39,6 +39,7 @@ import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
+import androidx.compose.foundation.overscroll
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
@@ -527,6 +528,7 @@ private fun SceneScope.SplitShade(
Box(
modifier =
Modifier.element(Shade.Elements.SplitShadeStartColumn)
+ .overscroll(verticalOverscrollEffect)
.weight(1f)
.graphicsLayer { translationX = unfoldTranslationXForStartSide }
) {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index 2d589f37f3cb..bb61a131dac3 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -108,7 +108,7 @@ internal class DraggableHandlerImpl(
swipes.updateSwipesResults(fromContent)
val result =
- swipes.findUserActionResult(overSlop)
+ (if (overSlop < 0f) swipes.upOrLeftResult else swipes.downOrRightResult)
// As we were unable to locate a valid target scene, the initial SwipeAnimation
// cannot be defined. Consequently, a simple NoOp Controller will be returned.
?: return NoOpDragController
@@ -448,27 +448,6 @@ internal class Swipes(val upOrLeft: Swipe.Resolved, val downOrRight: Swipe.Resol
this.upOrLeftResult = upOrLeftResult
this.downOrRightResult = downOrRightResult
}
-
- /**
- * Returns the [UserActionResult] in the direction of [directionOffset].
- *
- * @param directionOffset signed float that indicates the direction. Positive is down or right
- * negative is up or left.
- * @return null when there are no targets in either direction. If one direction is null and you
- * drag into the null direction this function will return the opposite direction, assuming
- * that the users intention is to start the drag into the other direction eventually. If
- * [directionOffset] is 0f and both direction are available, it will default to
- * [upOrLeftResult].
- */
- fun findUserActionResult(directionOffset: Float): UserActionResult? {
- return when {
- upOrLeftResult == null && downOrRightResult == null -> null
- (directionOffset < 0f && upOrLeftResult != null) || downOrRightResult == null ->
- upOrLeftResult
-
- else -> downOrRightResult
- }
- }
}
internal class NestedScrollHandlerImpl(
@@ -536,31 +515,6 @@ internal class NestedScrollHandlerImpl(
}
}
},
- canStartPostFling = { velocityAvailable ->
- val behavior: NestedScrollBehavior =
- when {
- velocityAvailable > 0f -> topOrLeftBehavior
- velocityAvailable < 0f -> bottomOrRightBehavior
- else -> return@PriorityNestedScrollConnection false
- }
-
- // We could start an overscroll animation
- canChangeScene = false
-
- val pointersDown: PointersInfo.PointersDown? =
- when (val info = pointersInfoOwner.pointersInfo()) {
- PointersInfo.MouseWheel -> {
- // Do not support mouse wheel interactions
- return@PriorityNestedScrollConnection false
- }
-
- is PointersInfo.PointersDown -> info
- null -> null
- }
- lastPointersDown = pointersDown
-
- behavior.canStartOnPostFling && shouldEnableSwipes()
- },
onStart = { firstScroll ->
scrollController(
dragController =
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
index 955be603efaf..9622fc151bb7 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
@@ -32,7 +32,7 @@ import androidx.compose.ui.platform.InspectorInfo
* not consumed by the [SceneTransitionLayout] unless specifically requested via
* [nestedScrollToScene].
*/
-enum class NestedScrollBehavior(val canStartOnPostFling: Boolean) {
+enum class NestedScrollBehavior {
/**
* Overscroll will only be used by the [SceneTransitionLayout] to move to the next scene if the
* gesture begins at the edge of the scrollable component (so that a scroll in that direction
@@ -42,7 +42,7 @@ enum class NestedScrollBehavior(val canStartOnPostFling: Boolean) {
* In addition, during scene transitions, scroll events are consumed by the
* [SceneTransitionLayout] instead of the scrollable component.
*/
- EdgeNoPreview(canStartOnPostFling = false),
+ EdgeNoPreview,
/**
* Overscroll will only be used by the [SceneTransitionLayout] to move to the next scene if the
@@ -52,7 +52,7 @@ enum class NestedScrollBehavior(val canStartOnPostFling: Boolean) {
* In addition, during scene transitions, scroll events are consumed by the
* [SceneTransitionLayout] instead of the scrollable component.
*/
- EdgeWithPreview(canStartOnPostFling = true),
+ @Deprecated("This will be removed, see b/378470603") EdgeWithPreview,
/**
* Any overscroll will be used by the [SceneTransitionLayout] to move to the next scene.
@@ -60,7 +60,7 @@ enum class NestedScrollBehavior(val canStartOnPostFling: Boolean) {
* In addition, during scene transitions, scroll events are consumed by the
* [SceneTransitionLayout] instead of the scrollable component.
*/
- EdgeAlways(canStartOnPostFling = true);
+ EdgeAlways;
companion object {
val Default = EdgeNoPreview
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
index 48f08a7086d6..952668ab49ff 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
@@ -111,6 +111,9 @@ interface SceneTransitionsBuilder {
* The overscroll animation always starts from a progress of 0f, and reaches 1f when moving the
* [distance] down/right, -1f when moving in the opposite direction.
*/
+ @Deprecated(
+ "Use verticalOverscrollEffect (or horizontalOverscrollEffect) directly from SceneScope."
+ )
fun overscroll(
content: ContentKey,
orientation: Orientation,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt
index 98a00173f1d7..b26bf55c85ec 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt
@@ -56,7 +56,6 @@ fun LargeTopAppBarNestedScrollConnection(
canStartPostScroll = { offsetAvailable, _, _ ->
offsetAvailable > 0 && height() < maxHeight()
},
- canStartPostFling = { false },
onStart = {
LargeTopAppBarScrollController(
height = height,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
index 3f182363e20c..3d0f182fffee 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/PriorityNestedScrollConnection.kt
@@ -24,7 +24,6 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.unit.Velocity
import com.android.compose.ui.util.SpaceVectorConverter
-import kotlin.math.sign
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
@@ -102,8 +101,8 @@ interface OnStopScope {
* over the default nested scrolling logic.
*
* When started, this connection intercepts scroll events *before* they reach child composables.
- * This "priority mode" is activated activated when either [canStartPreScroll], [canStartPostScroll]
- * or [canStartPostFling] returns `true`.
+ * This "priority mode" is activated when either [canStartPreScroll] or [canStartPostScroll] returns
+ * `true`.
*
* Once started, the [onStart] lambda provides a [ScrollController] to manage the scrolling. This
* controller allows you to directly manipulate the scroll state and define how scroll events are
@@ -123,8 +122,6 @@ interface OnStopScope {
* @param canStartPostScroll A lambda that returns `true` if the connection should enter priority
* mode during the post-scroll phase. This is called after child connections have consumed the
* scroll.
- * @param canStartPostFling A lambda that returns `true` if the connection should enter priority
- * mode during the post-fling phase. This is called after a fling gesture has been initiated.
* @param onStart A lambda that is called when the connection enters priority mode. It should return
* a [ScrollController] that will be used to control the scroll.
* @sample LargeTopAppBarNestedScrollConnection
@@ -136,7 +133,6 @@ class PriorityNestedScrollConnection(
(offsetAvailable: Float, offsetBeforeStart: Float, source: NestedScrollSource) -> Boolean,
private val canStartPostScroll:
(offsetAvailable: Float, offsetBeforeStart: Float, source: NestedScrollSource) -> Boolean,
- private val canStartPostFling: (velocityAvailable: Float) -> Boolean,
private val onStart: (firstScroll: Float) -> ScrollController,
) : NestedScrollConnection, SpaceVectorConverter by SpaceVectorConverter(orientation) {
@@ -233,17 +229,6 @@ class PriorityNestedScrollConnection(
return stop(velocity = availableFloat)
}
- // Check if post-fling condition is met, and start priority mode if necessary.
- // TODO(b/291053278): Remove canStartPostFling() and instead make it possible to define the
- // overscroll behavior on the Scene level.
- if (canStartPostFling(availableFloat)) {
- // The offset passed to onPriorityStart() must be != 0f, so we create a small offset of
- // 1px given the available velocity.
- val smallOffset = availableFloat.sign
- start(availableOffset = smallOffset)
- return stop(availableFloat)
- }
-
// Reset offset tracking after the fling gesture is finished.
resetOffsetTracker()
return Velocity.Zero
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
index b20056d54de1..6985644579f6 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
@@ -19,7 +19,9 @@ package com.android.compose.animation.scene
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.overscroll
import androidx.compose.material3.Text
+import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource.Companion.UserInput
@@ -102,7 +104,7 @@ class DraggableHandlerTest {
userActions =
mapOf(Swipe.Up to SceneB, Swipe.Up(fromSource = Edge.Bottom) to SceneA),
) {
- Text("SceneC")
+ Text("SceneC", Modifier.overscroll(verticalOverscrollEffect))
}
overlay(
key = OverlayA,
@@ -434,35 +436,12 @@ class DraggableHandlerTest {
}
@Test
- fun onDragIntoNoAction_startTransitionToOppositeDirection() = runGestureTest {
+ fun onDragIntoNoAction_stayIdle() = runGestureTest {
navigateToSceneC()
// We are on SceneC which has no action in Down direction
- val dragController = onDragStarted(overSlop = 10f)
- assertTransition(
- currentScene = SceneC,
- fromScene = SceneC,
- toScene = SceneB,
- progress = -0.1f,
- )
-
- // Reverse drag direction, it will consume the previous drag
- dragController.onDragDelta(pixels = -10f)
- assertTransition(
- currentScene = SceneC,
- fromScene = SceneC,
- toScene = SceneB,
- progress = 0.0f,
- )
-
- // Continue reverse drag direction, it should record progress to Scene B
- dragController.onDragDelta(pixels = -10f)
- assertTransition(
- currentScene = SceneC,
- fromScene = SceneC,
- toScene = SceneB,
- progress = 0.1f,
- )
+ onDragStarted(overSlop = 10f, expectedConsumedOverSlop = 0f)
+ assertIdle(currentScene = SceneC)
}
@Test
@@ -942,30 +921,6 @@ class DraggableHandlerTest {
}
@Test
- fun scrollFromIdleWithNoTargetScene_shouldUseOverscrollSpecIfAvailable() = runGestureTest {
- layoutState.transitions = transitions {
- overscroll(SceneC, Orientation.Vertical) { fade(TestElements.Foo) }
- }
- // Start at scene C.
- navigateToSceneC()
-
- val scene = layoutState.transitionState.currentScene
- // We should have overscroll spec for scene C
- assertThat(layoutState.transitions.overscrollSpec(scene, Orientation.Vertical)).isNotNull()
- assertThat(layoutState.currentTransition?.currentOverscrollSpec).isNull()
-
- val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeAlways)
- nestedScroll.scroll(available = downOffset(fractionOfScreen = 0.1f))
-
- // We scrolled down, under scene C there is nothing, so we can use the overscroll spec
- assertThat(layoutState.currentTransition?.currentOverscrollSpec).isNotNull()
- assertThat(layoutState.currentTransition?.currentOverscrollSpec?.content).isEqualTo(SceneC)
- val transition = layoutState.currentTransition
- assertThat(transition).isNotNull()
- assertThat(transition!!.progress).isEqualTo(-0.1f)
- }
-
- @Test
fun nestedScrollUseFromSourceInfo() = runGestureTest {
// Start at scene C.
navigateToSceneC()
@@ -1229,72 +1184,6 @@ class DraggableHandlerTest {
}
@Test
- fun overscroll_releaseAtNegativePercent_up() = runGestureTest {
- // Make Scene A overscrollable.
- layoutState.transitions = transitions {
- from(SceneA, to = SceneB) { spec = spring(dampingRatio = Spring.DampingRatioNoBouncy) }
- overscroll(SceneA, Orientation.Vertical) { fade(TestElements.Foo) }
- }
-
- mutableUserActionsA = mapOf(Swipe.Up to UserActionResult(SceneB))
-
- val middle = pointersDown(startedPosition = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f))
- val dragController = onDragStarted(pointersInfo = middle, overSlop = down(1f))
- val transition = assertThat(transitionState).isSceneTransition()
- assertThat(transition).hasFromScene(SceneA)
- assertThat(transition).hasToScene(SceneB)
- assertThat(transition).hasProgress(-1f)
-
- // Release to A.
- dragController.onDragStoppedAnimateNow(
- velocity = 0f,
- onAnimationStart = {
- assertTransition(fromScene = SceneA, toScene = SceneB, progress = -1f)
- },
- expectedConsumedVelocity = 0f,
- )
-
- // We kept the overscroll at 100% so that the placement logic didn't change at the end of
- // the animation.
- assertIdle(SceneA)
- assertThat(transition).hasProgress(0f)
- assertThat(transition).hasOverscrollSpec()
- }
-
- @Test
- fun overscroll_releaseAtNegativePercent_down() = runGestureTest {
- // Make Scene A overscrollable.
- layoutState.transitions = transitions {
- from(SceneA, to = SceneC) { spec = spring(dampingRatio = Spring.DampingRatioNoBouncy) }
- overscroll(SceneA, Orientation.Vertical) { fade(TestElements.Foo) }
- }
-
- mutableUserActionsA = mapOf(Swipe.Down to UserActionResult(SceneC))
-
- val middle = pointersDown(startedPosition = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f))
- val dragController = onDragStarted(pointersInfo = middle, overSlop = up(1f))
- val transition = assertThat(transitionState).isSceneTransition()
- assertThat(transition).hasFromScene(SceneA)
- assertThat(transition).hasToScene(SceneC)
- assertThat(transition).hasProgress(-1f)
-
- // Release to A.
- dragController.onDragStoppedAnimateNow(
- velocity = 0f,
- onAnimationStart = {
- assertTransition(fromScene = SceneA, toScene = SceneC, progress = -1f)
- },
- expectedConsumedVelocity = 0f,
- )
-
- // We kept the overscroll at 100% so that the placement logic didn't change at the end of
- // the animation.
- assertIdle(SceneA)
- assertThat(transition).hasProgress(0f)
- assertThat(transition).hasOverscrollSpec()
- }
-
- @Test
fun requireFullDistanceSwipe() = runGestureTest {
mutableUserActionsA +=
Swipe.Up to UserActionResult(SceneB, requiresFullDistanceSwipe = true)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index 4410e157b526..1959f5914821 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -1006,77 +1006,74 @@ class ElementTest {
@Test
fun elementTransitionDuringNestedScrollOverscroll() {
+ lateinit var density: Density
// The draggable touch slop, i.e. the min px distance a touch pointer must move before it is
// detected as a drag event.
var touchSlop = 0f
- val overscrollTranslateY = 10.dp
val layoutWidth = 200.dp
val layoutHeight = 400.dp
val state =
rule.runOnUiThread {
MutableSceneTransitionLayoutState(
- initialScene = SceneB,
- transitions =
- transitions {
- overscroll(SceneB, Orientation.Vertical) {
- progressConverter = ProgressConverter.linear()
- translate(TestElements.Foo, y = overscrollTranslateY)
- }
- },
+ initialScene = SceneA,
+ transitions = transitions { overscrollDisabled(SceneB, Orientation.Vertical) },
)
- as MutableSceneTransitionLayoutStateImpl
}
rule.setContent {
+ density = LocalDensity.current
touchSlop = LocalViewConfiguration.current.touchSlop
SceneTransitionLayout(
state = state,
modifier = Modifier.size(layoutWidth, layoutHeight),
) {
- scene(SceneA) { Spacer(Modifier.fillMaxSize()) }
- scene(SceneB, userActions = mapOf(Swipe.Up to SceneA)) {
+ scene(SceneA, userActions = mapOf(Swipe.Down to SceneB)) {
Box(
Modifier
// A scrollable that does not consume the scroll gesture
.scrollable(
- rememberScrollableState(consumeScrollDelta = { 0f }),
- Orientation.Vertical,
+ state = rememberScrollableState(consumeScrollDelta = { 0f }),
+ orientation = Orientation.Vertical,
)
.fillMaxSize()
- ) {
- Spacer(Modifier.element(TestElements.Foo).fillMaxSize())
- }
+ )
+ }
+ scene(SceneB) {
+ Spacer(
+ Modifier.overscroll(verticalOverscrollEffect)
+ .element(TestElements.Foo)
+ .fillMaxSize()
+ )
}
}
}
assertThat(state.transitionState).isIdle()
- val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag)
- fooElement.assertTopPositionInRootIsEqualTo(0.dp)
+ rule.onNodeWithTag(TestElements.Foo.testTag).assertDoesNotExist()
// Swipe by half of verticalSwipeDistance.
rule.onRoot().performTouchInput {
val middleTop = Offset((layoutWidth / 2).toPx(), 0f)
down(middleTop)
- // Scroll 50%
+ // Scroll 50%.
moveBy(Offset(0f, touchSlop + layoutHeight.toPx() * 0.5f), delayMillis = 1_000)
}
val transition = assertThat(state.transitionState).isSceneTransition()
- assertThat(transition).hasOverscrollSpec()
- assertThat(transition).hasProgress(-0.5f)
- fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 0.5f)
+ assertThat(transition).hasProgress(0.5f)
+ rule.onNodeWithTag(TestElements.Foo.testTag).assertTopPositionInRootIsEqualTo(0.dp)
rule.onRoot().performTouchInput {
- // Scroll another 100%
+ // Scroll another 100%.
moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000)
}
- // Scroll 150% (Scene B overscroll by 50%)
- assertThat(transition).hasProgress(-1.5f)
- assertThat(transition).hasOverscrollSpec()
- fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 1.5f)
+ // Scroll 150% (Scene B overscroll by 50%).
+ assertThat(transition).hasProgress(1f)
+ rule
+ .onNodeWithTag(TestElements.Foo.testTag)
+ .assertTopPositionInRootIsEqualTo(expectedOffset(layoutHeight * 0.5f, density))
}
@Test
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
index 28ea2d239b54..51483a894e1e 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt
@@ -39,7 +39,6 @@ import org.junit.runner.RunWith
class PriorityNestedScrollConnectionTest {
private var canStartPreScroll = false
private var canStartPostScroll = false
- private var canStartPostFling = false
private var canStopOnPreFling = true
private var isStarted = false
private var lastScroll: Float? = null
@@ -63,7 +62,6 @@ class PriorityNestedScrollConnectionTest {
orientation = Orientation.Vertical,
canStartPreScroll = { _, _, _ -> canStartPreScroll },
canStartPostScroll = { _, _, _ -> canStartPostScroll },
- canStartPostFling = { canStartPostFling },
onStart = { _ ->
isStarted = true
object : ScrollController {
@@ -239,36 +237,6 @@ class PriorityNestedScrollConnectionTest {
}
@Test
- fun receive_onPostFling() = runTest {
- canStartPostFling = true
-
- scrollConnection.onPostFling(consumed = Velocity(1f, 1f), available = Velocity(2f, 2f))
-
- assertThat(lastStop).isEqualTo(2f)
- }
-
- @Test
- fun step1_priorityModeShouldStartOnlyOnPostFling() = runTest {
- canStartPostFling = true
-
- scrollConnection.onPreScroll(available = Offset.Zero, source = UserInput)
- assertThat(isStarted).isEqualTo(false)
-
- scrollConnection.onPostScroll(
- consumed = Offset.Zero,
- available = Offset.Zero,
- source = UserInput,
- )
- assertThat(isStarted).isEqualTo(false)
-
- scrollConnection.onPreFling(available = Velocity.Zero)
- assertThat(isStarted).isEqualTo(false)
-
- scrollConnection.onPostFling(consumed = Velocity.Zero, available = Velocity.Zero)
- assertThat(isStarted).isEqualTo(true)
- }
-
- @Test
fun handleMultipleOnPreFlingCalls() = runTest {
startPriorityModePostScroll()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
index e5f0d7c6bf37..68f4acde7609 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
@@ -42,6 +42,7 @@ import com.android.systemui.flags.andSceneContainer
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -494,6 +495,7 @@ class CommunalSceneStartableTest(flags: FlagsParameterization) : SysuiTestCase()
// Start dreaming.
updateDreaming(true)
+ advanceTimeBy(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS)
// Hub times out immediately.
assertThat(scene).isEqualTo(CommunalScenes.Blank)
@@ -650,6 +652,7 @@ class CommunalSceneStartableTest(flags: FlagsParameterization) : SysuiTestCase()
// Start dreaming.
updateDreaming(true)
+ advanceTimeBy(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS)
// Hub times out immediately.
assertThat(scene).isEqualTo(Scenes.Dream)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index 79bb0c401e78..06dd046564df 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -74,6 +74,7 @@ import com.android.systemui.keyguard.data.repository.fakeTrustRepository
import com.android.systemui.keyguard.data.repository.keyguardRepository
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.keyguard.dismissCallbackRegistry
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.dozeInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardEnabledInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
@@ -1270,8 +1271,11 @@ class SceneContainerStartableTest : SysuiTestCase() {
authenticationMethod = AuthenticationMethodModel.None,
isLockscreenEnabled = false,
)
- assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+ powerInteractor.setAsleepForTest()
underTest.start()
+ runCurrent()
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+
powerInteractor.setAwakeForTest()
runCurrent()
@@ -2139,6 +2143,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val transitionStateFlow = prepareState()
underTest.start()
+ runCurrent()
emulateSceneTransition(transitionStateFlow, toScene = Scenes.Bouncer)
assertThat(currentScene).isNotEqualTo(Scenes.Lockscreen)
@@ -2153,6 +2158,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
val currentScene by collectLastValue(sceneInteractor.currentScene)
val transitionStateFlow = prepareState()
underTest.start()
+ runCurrent()
emulateSceneTransition(transitionStateFlow, toScene = Scenes.Bouncer)
assertThat(currentScene).isEqualTo(Scenes.Bouncer)
@@ -2269,6 +2275,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
assertThat(currentScene).isEqualTo(Scenes.Gone)
assertThat(kosmos.deviceEntryInteractor.isDeviceEntered.value).isTrue()
underTest.start()
+ runCurrent()
sceneInteractor.changeScene(Scenes.Shade, "")
assertThat(currentScene).isEqualTo(Scenes.Shade)
assertThat(kosmos.deviceEntryInteractor.isDeviceEntered.value).isTrue()
@@ -2350,6 +2357,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
val currentScene by collectLastValue(sceneInteractor.currentScene)
prepareState()
underTest.start()
+ runCurrent()
// run all pending dismiss succeeded/cancelled calls from setup:
kosmos.fakeExecutor.runAllReady()
@@ -2461,13 +2469,18 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchFromDreamToLockscreen_whenLockedAndDreamStopped() =
testScope.runTest {
- keyguardInteractor.setDreaming(true)
val currentScene by collectLastValue(sceneInteractor.currentScene)
prepareState(initialSceneKey = Scenes.Dream)
- assertThat(currentScene).isEqualTo(Scenes.Dream)
underTest.start()
+ advanceTimeBy(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS)
+ runCurrent()
+ keyguardInteractor.setDreaming(true)
+ advanceTimeBy(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS)
+ runCurrent()
+ assertThat(currentScene).isEqualTo(Scenes.Dream)
keyguardInteractor.setDreaming(false)
+ advanceTimeBy(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS)
runCurrent()
assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
}
@@ -2475,13 +2488,18 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchFromDreamToGone_whenUnlockedAndDreamStopped() =
testScope.runTest {
- keyguardInteractor.setDreaming(true)
val currentScene by collectLastValue(sceneInteractor.currentScene)
prepareState(initialSceneKey = Scenes.Dream, isDeviceUnlocked = true)
- assertThat(currentScene).isEqualTo(Scenes.Dream)
underTest.start()
+ advanceTimeBy(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS)
+ runCurrent()
+ keyguardInteractor.setDreaming(true)
+ advanceTimeBy(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS)
+ runCurrent()
+ assertThat(currentScene).isEqualTo(Scenes.Dream)
keyguardInteractor.setDreaming(false)
+ advanceTimeBy(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS)
runCurrent()
assertThat(currentScene).isEqualTo(Scenes.Gone)
}
@@ -2684,6 +2702,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
underTest.start()
val currentScene by collectLastValue(sceneInteractor.currentScene)
val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ runCurrent()
sceneInteractor.changeScene(Scenes.Shade, "reason")
sceneInteractor.showOverlay(Overlays.NotificationsShade, "reason")
assertThat(currentScene).isEqualTo(Scenes.Shade)
@@ -2835,8 +2854,15 @@ class SceneContainerStartableTest : SysuiTestCase() {
)
sceneInteractor.setTransitionState(transitionStateFlow)
initialSceneKey?.let {
+ if (isDeviceUnlocked && initialSceneKey != Scenes.Gone) {
+ // Pass through the Gone scene to populate device entry state properly.
+ transitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Gone)
+ sceneInteractor.changeScene(Scenes.Gone, "prepareState, passing through Gone scene")
+ runCurrent()
+ }
+
transitionStateFlow.value = ObservableTransitionState.Idle(it)
- sceneInteractor.changeScene(it, "reason")
+ sceneInteractor.changeScene(it, "prepareState, initialSceneKey isn't null")
}
if (startsAwake) {
powerInteractor.setAwakeForTest()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/domain/interactor/KeyguardBypassInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/domain/interactor/KeyguardBypassInteractorTest.kt
index c90183df9847..1cc55bf87b1a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/domain/interactor/KeyguardBypassInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/domain/interactor/KeyguardBypassInteractorTest.kt
@@ -127,12 +127,6 @@ class KeyguardBypassInteractorTest : SysuiTestCase() {
kosmos.configureKeyguardBypass(isBypassAvailable = skipIsBypassAvailableCheck)
underTest = kosmos.keyguardBypassInteractor
- // bouncerShowing false, !onLockscreenScene false
- // !onLockscreenScene false
- setScene(
- bouncerShowing = !skipBouncerShowingCheck,
- onLockscreenScene = skipOnLockscreenSceneCheck,
- )
// alternateBouncerShowing false
setAlternateBouncerShowing(!skipAlternateBouncerShowingCheck)
// launchingAffordance false
@@ -141,6 +135,13 @@ class KeyguardBypassInteractorTest : SysuiTestCase() {
setPulseExpanding(!skipPulseExpandingCheck)
// qsExpanding false
setQsExpanded(!skipQsExpandedCheck)
+
+ // bouncerShowing false, !onLockscreenScene false
+ // !onLockscreenScene false
+ setScene(
+ bouncerShowing = !skipBouncerShowingCheck,
+ onLockscreenScene = skipOnLockscreenSceneCheck,
+ )
}
private fun setAlternateBouncerShowing(alternateBouncerVisible: Boolean) {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index 5644e6b3b9bf..34679b08cf20 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -183,7 +183,12 @@ constructor(
this@CommunalSceneStartable.isDreaming = isDreaming
if (scene.isCommunal() && isDreaming && timeoutJob == null) {
// If dreaming starts after timeout has expired, ex. if dream restarts under
- // the hub, just close the hub immediately.
+ // the hub, wait for IS_ABLE_TO_DREAM_DELAY_MS and then close the hub. The
+ // delay is necessary so the KeyguardInteractor.isAbleToDream flow passes
+ // through that same amount of delay and publishes a new value which is then
+ // picked up by the HomeSceneFamilyResolver such that the next call to
+ // SceneInteractor.changeScene(Home) will resolve "Home" to "Dream".
+ delay(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS)
communalSceneInteractor.changeScene(
CommunalScenes.Blank,
"dream started after timeout",
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 26c286df01d7..0d9474e07ce7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -200,7 +200,10 @@ constructor(
* Dozing and dreaming have overlapping events. If the doze state remains in FINISH, it means
* that doze mode is not running and DREAMING is ok to commence.
*
- * Allow a brief moment to prevent rapidly oscillating between true/false signals.
+ * Allow a brief moment to prevent rapidly oscillating between true/false signals. The amount of
+ * time is [IS_ABLE_TO_DREAM_DELAY_MS] - consumers should consider waiting for that long before
+ * examining the value of this flow, to let other consumers have enough time to also see that
+ * same new value.
*/
val isAbleToDream: Flow<Boolean> =
dozeTransitionModel
@@ -212,7 +215,7 @@ constructor(
// do not immediately process any dreaming information when exiting AOD. It
// should actually be quite strange to leave AOD and then go straight to
// DREAMING so this should be fine.
- delay(500L)
+ delay(IS_ABLE_TO_DREAM_DELAY_MS)
isDreaming
.sample(powerInteractor.isAwake) { isDreaming, isAwake ->
isDreaming && isAwake
@@ -550,5 +553,11 @@ constructor(
companion object {
private const val TAG = "KeyguardInteractor"
+ /**
+ * Amount of time that [KeyguardInteractor.isAbleToDream] is delayed; consumers of that flow
+ * should consider waiting this amount of time before check the value of this flow, to let
+ * other consumers have enough time to see the new value.
+ */
+ const val IS_ABLE_TO_DREAM_DELAY_MS = 500L
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 1204cde19c76..2a23620839e5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -74,7 +74,7 @@ constructor(
context: Context,
logger: MediaTttReceiverLogger,
viewCaptureAwareWindowManager: ViewCaptureAwareWindowManager,
- @Main mainExecutor: DelayableExecutor,
+ @Main private val mainExecutor: DelayableExecutor,
accessibilityManager: AccessibilityManager,
configurationController: ConfigurationController,
dumpManager: DumpManager,
@@ -285,6 +285,14 @@ constructor(
} else {
rippleController.collapseRipple(rippleView, onAnimationEnd)
animateViewTranslationAndFade(iconContainerView, translationYBy, 0f)
+ mainExecutor.executeDelayed(
+ {
+ if (view.isAttachedToWindow) {
+ onAnimationEnd.run()
+ }
+ },
+ ICON_TRANSLATION_ANIM_DURATION,
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index d83d74e4e538..0e6fc36fb96a 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -230,13 +230,7 @@ constructor(
) {
val currentSceneKey = currentScene.value
val resolvedScene = sceneFamilyResolvers.get()[toScene]?.resolvedScene?.value ?: toScene
- if (
- !validateSceneChange(
- from = currentSceneKey,
- to = resolvedScene,
- loggingReason = loggingReason,
- )
- ) {
+ if (!validateSceneChange(to = resolvedScene, loggingReason = loggingReason)) {
return
}
@@ -268,13 +262,7 @@ constructor(
familyResolver.resolvedScene.value
}
} ?: toScene
- if (
- !validateSceneChange(
- from = currentSceneKey,
- to = resolvedScene,
- loggingReason = loggingReason,
- )
- ) {
+ if (!validateSceneChange(to = resolvedScene, loggingReason = loggingReason)) {
return
}
@@ -458,12 +446,11 @@ constructor(
* Will throw a runtime exception for illegal states (for example, attempting to change to a
* scene that's not part of the current scene framework configuration).
*
- * @param from The current scene being transitioned away from
* @param to The desired destination scene to transition to
* @param loggingReason The reason why the transition is requested, for logging purposes
* @return `true` if the scene change is valid; `false` if it shouldn't happen
*/
- private fun validateSceneChange(from: SceneKey, to: SceneKey, loggingReason: String): Boolean {
+ private fun validateSceneChange(to: SceneKey, loggingReason: String): Boolean {
if (to !in repository.allContentKeys) {
return false
}
@@ -486,7 +473,7 @@ constructor(
" Logging reason for scene change was: $loggingReason"
}
- return from != to
+ return true
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt
index b89eb5c762e0..2a0a22f32601 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt
@@ -26,6 +26,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardEnabledInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.util.kotlin.combine
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoSet
@@ -34,7 +35,6 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
/**
@@ -59,6 +59,7 @@ constructor(
deviceEntryInteractor.isDeviceEntered,
deviceEntryInteractor.isUnlocked,
keyguardInteractor.isDreamingWithOverlay,
+ keyguardInteractor.isAbleToDream,
transform = ::homeScene,
)
.stateIn(
@@ -71,6 +72,7 @@ constructor(
isDeviceEntered = deviceEntryInteractor.isDeviceEntered.value,
isUnlocked = deviceEntryInteractor.isUnlocked.value,
isDreamingWithOverlay = false,
+ isAbleToDream = false,
),
)
@@ -82,10 +84,11 @@ constructor(
isDeviceEntered: Boolean,
isUnlocked: Boolean,
isDreamingWithOverlay: Boolean,
+ isAbleToDream: Boolean,
): SceneKey =
when {
// Dream can run even if Keyguard is disabled, thus it has the highest priority here.
- isDreamingWithOverlay -> Scenes.Dream
+ isDreamingWithOverlay && isAbleToDream -> Scenes.Dream
!isKeyguardEnabled -> Scenes.Gone
canSwipeToEnter == true -> Scenes.Lockscreen
!isDeviceEntered -> Scenes.Lockscreen
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 072089981cc7..7c9d850eaf07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -1284,7 +1284,11 @@ public class NotificationStackScrollLayout
@Override
public void setStackCutoff(float stackCutoff) {
if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
- mAmbientState.setStackCutoff(stackCutoff);
+ if (mAmbientState.getStackCutoff() != stackCutoff) {
+ mAmbientState.setStackCutoff(stackCutoff);
+ updateStackEndHeightAndStackHeight(mAmbientState.getExpansionFraction());
+ requestChildrenUpdate();
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
index c5bef99f9307..ef68b4de5291 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
@@ -109,11 +109,6 @@ constructor(
}
}
launch {
- viewModel.shouldResetStackTop
- .filter { it }
- .collectTraced { view.setStackTop(-(view.getHeadsUpInset().toFloat())) }
- }
- launch {
viewModel.shouldCloseGuts
.filter { it }
.collectTraced { view.closeGutsOnSceneTouch() }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
index 56b335648138..1bb205cbcb61 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
@@ -192,12 +192,6 @@ constructor(
/** Whether we should close any open notification guts. */
val shouldCloseGuts: Flow<Boolean> = stackAppearanceInteractor.shouldCloseGuts
- val shouldResetStackTop: Flow<Boolean> =
- sceneInteractor.transitionState
- .mapNotNull { state -> state is Idle && state.currentScene == Scenes.Gone }
- .distinctUntilChanged()
- .dumpWhileCollecting("shouldResetStackTop")
-
/** Whether the Notification Stack is visibly on the lockscreen scene. */
val isShowingStackOnLockscreen: Flow<Boolean> =
sceneInteractor.transitionState
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 99467cb11282..a91fb45c9c80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -95,6 +95,7 @@ import com.android.systemui.statusbar.notification.emptyshade.ui.view.EmptyShade
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor;
import com.android.systemui.statusbar.notification.footer.shared.NotifRedesignFooter;
import com.android.systemui.statusbar.notification.footer.ui.view.FooterView;
+import com.android.systemui.statusbar.notification.headsup.AvalancheController;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
@@ -103,7 +104,6 @@ import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrim
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
-import com.android.systemui.statusbar.notification.headsup.AvalancheController;
import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor;
@@ -356,6 +356,31 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
@EnableSceneContainer
+ public void updateStackCutoff_updatesStackEndHeight() {
+ // GIVEN shade is fully open
+ final float stackTop = 200f;
+ final float stackCutoff = 1000f;
+ final float stackHeight = stackCutoff - stackTop;
+ mAmbientState.setStackTop(stackTop);
+ mAmbientState.setStackCutoff(stackCutoff);
+ mAmbientState.setStatusBarState(StatusBarState.SHADE);
+ mStackScroller.setMaxDisplayedNotifications(-1); // no limit on the shade
+ mStackScroller.setExpandFraction(1f); // shade is fully expanded
+ assertThat(mAmbientState.getStackEndHeight()).isEqualTo(stackHeight);
+ assertThat(mAmbientState.getInterpolatedStackHeight()).isEqualTo(stackHeight);
+
+ // WHEN stackCutoff changes
+ final float newStackCutoff = 800;
+ mStackScroller.setStackCutoff(newStackCutoff);
+
+ // THEN stackEndHeight is updated
+ final float newStackHeight = newStackCutoff - stackTop;
+ assertThat(mAmbientState.getStackEndHeight()).isEqualTo(newStackHeight);
+ assertThat(mAmbientState.getInterpolatedStackHeight()).isEqualTo(newStackHeight);
+ }
+
+ @Test
+ @EnableSceneContainer
public void updateStackEndHeightAndStackHeight_maxNotificationsSet_withSceneContainer() {
float stackHeight = 300f;
when(mStackSizeCalculator.computeHeight(eq(mStackScroller), anyInt(), anyFloat()))
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt
index 6944e6c14096..ab193d294b8c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt
@@ -261,7 +261,7 @@ class ShadeTestUtilSceneImpl(
}
private fun setIdleScene(scene: SceneKey) {
- sceneInteractor.changeScene(scene, "test")
+ sceneInteractor.changeScene(scene, "ShadeTestUtil.setIdleScene")
val transitionState =
MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(scene))
sceneInteractor.setTransitionState(transitionState)
@@ -274,7 +274,7 @@ class ShadeTestUtilSceneImpl(
progress: Float,
isInitiatedByUserInput: Boolean = true,
) {
- sceneInteractor.changeScene(from, "test")
+ sceneInteractor.changeScene(from, "ShadeTestUtil.setTransitionProgress")
val transitionState =
MutableStateFlow<ObservableTransitionState>(
ObservableTransitionState.Transition(
diff --git a/services/art-wear-profile b/services/art-wear-profile
index 1e3090f9bf00..f080715643ca 100644
--- a/services/art-wear-profile
+++ b/services/art-wear-profile
@@ -7419,7 +7419,7 @@ PLcom/android/server/app/GameManagerService;->sendUserMessage(IILjava/lang/Strin
PLcom/android/server/app/GameManagerService;->updateConfigsForUser(IZ[Ljava/lang/String;)V
PLcom/android/server/app/GameManagerService;->writeGameModeInterventionsToFile(I)V
PLcom/android/server/app/GameManagerSettings;-><init>(Ljava/io/File;)V
-HPLcom/android/server/app/GameManagerSettings;->getConfigOverride(Ljava/lang/String;)Lcom/android/server/app/GameManagerService$GamePackageConfiguration;
+HPLcom/android/server/app/GameManagerSettings;->getConfigOverrideLocked(Ljava/lang/String;)Lcom/android/server/app/GameManagerService$GamePackageConfiguration;
HPLcom/android/server/app/GameManagerSettings;->getGameModeLocked(Ljava/lang/String;)I
PLcom/android/server/app/GameManagerSettings;->readPersistentDataLocked()Z
PLcom/android/server/appbinding/AppBindingConstants;-><init>(Ljava/lang/String;)V
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index f42641ece09b..aadf6f61956c 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -2840,7 +2840,6 @@ public class OomAdjuster {
return true;
}
}
- capability |= PROCESS_CAPABILITY_CPU_TIME;
}
// Not doing bind OOM management, so treat
// this guy more like a started service.
@@ -3089,7 +3088,6 @@ public class OomAdjuster {
return true;
}
}
- capability |= PROCESS_CAPABILITY_CPU_TIME;
}
}
if (cr.hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)) {
@@ -4243,6 +4241,11 @@ public class OomAdjuster {
!= client.getSetCapability()) {
// The connection might elevate the importance of the service's capabilities.
needDryRun = true;
+ } else if (Flags.useCpuTimeCapability()
+ && (client.getSetCapability() & ~app.getSetCapability()
+ & PROCESS_CAPABILITY_CPU_TIME) != 0) {
+ // The connection might grant PROCESS_CAPABILITY_CPU_TIME to the service.
+ needDryRun = true;
} else if (Flags.unfreezeBindPolicyFix()
&& cr.hasFlag(Context.BIND_WAIVE_PRIORITY
| Context.BIND_ALLOW_OOM_MANAGEMENT)) {
@@ -4290,6 +4293,10 @@ public class OomAdjuster {
&& client.mOptRecord.shouldNotFreeze()) {
// Process has shouldNotFreeze and it could have gotten it from the client.
return true;
+ } else if (Flags.useCpuTimeCapability()
+ && (client.getSetCapability() & app.getSetCapability()
+ & PROCESS_CAPABILITY_CPU_TIME) != 0) {
+ return true;
}
return false;
}
@@ -4309,6 +4316,11 @@ public class OomAdjuster {
&& client.mOptRecord.shouldNotFreeze()
&& !app.mOptRecord.shouldNotFreeze()) {
needDryRun = true;
+ } else if (Flags.useCpuTimeCapability()
+ && (client.getSetCapability() & ~app.getSetCapability()
+ & PROCESS_CAPABILITY_CPU_TIME) != 0) {
+ // The connection might grant PROCESS_CAPABILITY_CPU_TIME to the provider.
+ needDryRun = true;
}
if (needDryRun) {
@@ -4335,6 +4347,10 @@ public class OomAdjuster {
&& client.mOptRecord.shouldNotFreeze()) {
// Process has shouldNotFreeze and it could have gotten it from the client.
return true;
+ } else if (Flags.useCpuTimeCapability()
+ && (client.getSetCapability() & app.getSetCapability()
+ & PROCESS_CAPABILITY_CPU_TIME) != 0) {
+ return true;
}
return false;
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 6f8dc105850d..c0a97db7275b 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -1423,10 +1423,10 @@ public final class GameManagerService extends IGameManagerService.Stub {
}
final GameManagerSettings settings = mSettings.get(userId);
// look for the existing GamePackageConfiguration override
- configOverride = settings.getConfigOverride(packageName);
+ configOverride = settings.getConfigOverrideLocked(packageName);
if (configOverride == null) {
configOverride = new GamePackageConfiguration(packageName);
- settings.setConfigOverride(packageName, configOverride);
+ settings.setConfigOverrideLocked(packageName, configOverride);
}
}
GamePackageConfiguration.GameModeConfiguration internalConfig =
@@ -1759,10 +1759,10 @@ public final class GameManagerService extends IGameManagerService.Stub {
}
final GameManagerSettings settings = mSettings.get(userId);
// look for the existing GamePackageConfiguration override
- configOverride = settings.getConfigOverride(packageName);
+ configOverride = settings.getConfigOverrideLocked(packageName);
if (configOverride == null) {
configOverride = new GamePackageConfiguration(packageName);
- settings.setConfigOverride(packageName, configOverride);
+ settings.setConfigOverrideLocked(packageName, configOverride);
}
}
// modify GameModeConfiguration intervention settings
@@ -1801,7 +1801,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
}
final GameManagerSettings settings = mSettings.get(userId);
if (gameModeToReset != -1) {
- final GamePackageConfiguration configOverride = settings.getConfigOverride(
+ final GamePackageConfiguration configOverride = settings.getConfigOverrideLocked(
packageName);
if (configOverride == null) {
return;
@@ -1812,10 +1812,10 @@ public final class GameManagerService extends IGameManagerService.Stub {
}
configOverride.removeModeConfig(gameModeToReset);
if (!configOverride.hasActiveGameModeConfig()) {
- settings.removeConfigOverride(packageName);
+ settings.removeConfigOverrideLocked(packageName);
}
} else {
- settings.removeConfigOverride(packageName);
+ settings.removeConfigOverrideLocked(packageName);
}
}
@@ -2030,7 +2030,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
synchronized (mLock) {
if (mSettings.containsKey(userId)) {
- overrideConfig = mSettings.get(userId).getConfigOverride(packageName);
+ overrideConfig = mSettings.get(userId).getConfigOverrideLocked(packageName);
}
}
if (overrideConfig == null || config == null) {
@@ -2075,7 +2075,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
}
synchronized (mLock) {
if (mSettings.containsKey(userId)) {
- mSettings.get(userId).removeGame(packageName);
+ mSettings.get(userId).removeGameLocked(packageName);
}
sendUserMessage(userId, WRITE_SETTINGS,
Intent.ACTION_PACKAGE_REMOVED, WRITE_DELAY_MILLIS);
diff --git a/services/core/java/com/android/server/app/GameManagerSettings.java b/services/core/java/com/android/server/app/GameManagerSettings.java
index b084cf3c3b12..c57a1f73d7d7 100644
--- a/services/core/java/com/android/server/app/GameManagerSettings.java
+++ b/services/core/java/com/android/server/app/GameManagerSettings.java
@@ -116,7 +116,7 @@ public class GameManagerSettings {
* Removes all game settings of a given package.
* This operation must be synced with an external lock.
*/
- void removeGame(String packageName) {
+ void removeGameLocked(String packageName) {
mGameModes.remove(packageName);
mConfigOverrides.remove(packageName);
}
@@ -125,7 +125,7 @@ public class GameManagerSettings {
* Returns the game config override of a given package or null if absent.
* This operation must be synced with an external lock.
*/
- GamePackageConfiguration getConfigOverride(String packageName) {
+ GamePackageConfiguration getConfigOverrideLocked(String packageName) {
return mConfigOverrides.get(packageName);
}
@@ -133,7 +133,7 @@ public class GameManagerSettings {
* Sets the game config override of a given package.
* This operation must be synced with an external lock.
*/
- void setConfigOverride(String packageName, GamePackageConfiguration configOverride) {
+ void setConfigOverrideLocked(String packageName, GamePackageConfiguration configOverride) {
mConfigOverrides.put(packageName, configOverride);
}
@@ -141,7 +141,7 @@ public class GameManagerSettings {
* Removes the game mode config override of a given package.
* This operation must be synced with an external lock.
*/
- void removeConfigOverride(String packageName) {
+ void removeConfigOverrideLocked(String packageName) {
mConfigOverrides.remove(packageName);
}
diff --git a/services/core/java/com/android/server/display/BrightnessRangeController.java b/services/core/java/com/android/server/display/BrightnessRangeController.java
index 83b0801ce87f..50d650855b05 100644
--- a/services/core/java/com/android/server/display/BrightnessRangeController.java
+++ b/services/core/java/com/android/server/display/BrightnessRangeController.java
@@ -37,7 +37,6 @@ class BrightnessRangeController {
private final HdrClamper mHdrClamper;
private final Runnable mModeChangeCallback;
- private final boolean mUseNbmController;
private final boolean mUseHdrClamper;
@@ -62,11 +61,8 @@ class BrightnessRangeController {
mHdrClamper = hdrClamper;
mNormalBrightnessModeController = normalBrightnessModeController;
mUseHdrClamper = flags.isHdrClamperEnabled() && !flags.useNewHdrBrightnessModifier();
- mUseNbmController = flags.isNbmControllerEnabled();
- if (mUseNbmController) {
- mNormalBrightnessModeController.resetNbmData(
- displayDeviceConfig.getLuxThrottlingData());
- }
+ mNormalBrightnessModeController.resetNbmData(
+ displayDeviceConfig.getLuxThrottlingData());
if (flags.useNewHdrBrightnessModifier()) {
// HDR boost is handled by HdrBrightnessModifier and should be disabled in HbmController
mHbmController.disableHdrBoost();
@@ -76,7 +72,6 @@ class BrightnessRangeController {
void dump(PrintWriter pw) {
pw.println("BrightnessRangeController:");
- pw.println(" mUseNormalBrightnessController=" + mUseNbmController);
pw.println(" mUseHdrClamper=" + mUseHdrClamper);
mHbmController.dump(pw);
mNormalBrightnessModeController.dump(pw);
@@ -138,9 +133,7 @@ class BrightnessRangeController {
float getCurrentBrightnessMax() {
// nbmController might adjust maxBrightness only if device does not support HBM or
// hbm is currently not allowed
- if (mUseNbmController
- && (!mHbmController.deviceSupportsHbm()
- || !mHbmController.isHbmCurrentlyAllowed())) {
+ if (!mHbmController.deviceSupportsHbm() || !mHbmController.isHbmCurrentlyAllowed()) {
return Math.min(mHbmController.getCurrentBrightnessMax(),
mNormalBrightnessModeController.getCurrentBrightnessMax());
}
@@ -173,16 +166,12 @@ class BrightnessRangeController {
}
private void applyChanges(BooleanSupplier nbmChangesFunc, Runnable hbmChangesFunc) {
- if (mUseNbmController) {
- boolean nbmTransitionChanged = nbmChangesFunc.getAsBoolean();
- hbmChangesFunc.run();
- // if nbm transition changed - trigger callback
- // HighBrightnessModeController handles sending changes itself
- if (nbmTransitionChanged) {
- mModeChangeCallback.run();
- }
- } else {
- hbmChangesFunc.run();
+ boolean nbmTransitionChanged = nbmChangesFunc.getAsBoolean();
+ hbmChangesFunc.run();
+ // if nbm transition changed - trigger callback
+ // HighBrightnessModeController handles sending changes itself
+ if (nbmTransitionChanged) {
+ mModeChangeCallback.run();
}
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index f48fbea64f65..9387e9ede532 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1646,6 +1646,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
(mBrightnessReasonTemp.getReason() == BrightnessReason.REASON_TEMPORARY)
|| mAutomaticBrightnessStrategy
.isTemporaryAutoBrightnessAdjustmentApplied();
+ float rampSpeed = 0;
if (!mPendingScreenOff) {
if (mSkipScreenOnBrightnessRamp) {
if (state == Display.STATE_ON) {
@@ -1747,7 +1748,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
customAnimationRate, /* ignoreAnimationLimits = */true);
} else {
boolean isIncreasing = animateValue > currentBrightness;
- final float rampSpeed;
final boolean idle = mAutomaticBrightnessController != null
&& mAutomaticBrightnessController.isInIdleMode();
if (isIncreasing && slowChange) {
@@ -1832,6 +1832,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
.getDisplayBrightnessStrategyName());
mTempBrightnessEvent.setAutomaticBrightnessEnabled(
displayBrightnessState.getShouldUseAutoBrightness());
+ mTempBrightnessEvent.setSlowChange(slowChange);
+ mTempBrightnessEvent.setRampSpeed(rampSpeed);
// Temporary is what we use during slider interactions. We avoid logging those so that
// we don't spam logcat when the slider is being used.
boolean tempToTempTransition =
diff --git a/services/core/java/com/android/server/display/brightness/BrightnessEvent.java b/services/core/java/com/android/server/display/brightness/BrightnessEvent.java
index 9e9b899ffa7d..159c30ddf77f 100644
--- a/services/core/java/com/android/server/display/brightness/BrightnessEvent.java
+++ b/services/core/java/com/android/server/display/brightness/BrightnessEvent.java
@@ -78,6 +78,8 @@ public final class BrightnessEvent {
private String mDisplayBrightnessStrategyName;
@AutomaticBrightnessController.AutomaticBrightnessMode
private int mAutoBrightnessMode;
+ private boolean mSlowChange;
+ private float mRampSpeed;
public BrightnessEvent(BrightnessEvent that) {
copyFrom(that);
@@ -126,6 +128,8 @@ public final class BrightnessEvent {
mAutomaticBrightnessEnabled = that.isAutomaticBrightnessEnabled();
mDisplayBrightnessStrategyName = that.getDisplayBrightnessStrategyName();
mAutoBrightnessMode = that.mAutoBrightnessMode;
+ mSlowChange = that.mSlowChange;
+ mRampSpeed = that.mRampSpeed;
}
/**
@@ -163,6 +167,8 @@ public final class BrightnessEvent {
mAutomaticBrightnessEnabled = true;
mDisplayBrightnessStrategyName = "";
mAutoBrightnessMode = AUTO_BRIGHTNESS_MODE_DEFAULT;
+ mSlowChange = false;
+ mRampSpeed = 0;
}
/**
@@ -248,7 +254,9 @@ public final class BrightnessEvent {
+ ", powerFactor=" + mPowerFactor
// Meta
+ ", physDisp=" + mPhysicalDisplayName + "(" + mPhysicalDisplayId + ")"
- + ", logicalId=" + mDisplayId;
+ + ", logicalId=" + mDisplayId
+ + ", slowChange=" + mSlowChange
+ + ", rampSpeed=" + mRampSpeed;
}
@Override
@@ -469,8 +477,8 @@ public final class BrightnessEvent {
return mDisplayBrightnessStrategyName;
}
- public void setAutomaticBrightnessEnabled(boolean mAutomaticBrightnessEnabled) {
- this.mAutomaticBrightnessEnabled = mAutomaticBrightnessEnabled;
+ public void setAutomaticBrightnessEnabled(boolean automaticBrightnessEnabled) {
+ mAutomaticBrightnessEnabled = automaticBrightnessEnabled;
}
@AutomaticBrightnessController.AutomaticBrightnessMode
@@ -483,6 +491,14 @@ public final class BrightnessEvent {
mAutoBrightnessMode = mode;
}
+ public void setSlowChange(boolean slowChange) {
+ mSlowChange = slowChange;
+ }
+
+ public void setRampSpeed(float rampSpeed) {
+ mRampSpeed = rampSpeed;
+ }
+
/**
* A utility to stringify flags from a BrightnessEvent
* @return Stringified flags from BrightnessEvent
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index 7892639fc8ed..52e64905c984 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -168,8 +168,7 @@ public final class ColorDisplayService extends SystemService {
new NightDisplayTintController();
private final TintController mGlobalSaturationTintController =
new GlobalSaturationTintController();
- private final ReduceBrightColorsTintController mReduceBrightColorsTintController =
- new ReduceBrightColorsTintController();
+ private final ReduceBrightColorsTintController mReduceBrightColorsTintController;
@VisibleForTesting
final Handler mHandler;
@@ -201,7 +200,13 @@ public final class ColorDisplayService extends SystemService {
private boolean mEvenDimmerActivated;
public ColorDisplayService(Context context) {
+ this(context, new ReduceBrightColorsTintController());
+ }
+
+ @VisibleForTesting
+ public ColorDisplayService(Context context, ReduceBrightColorsTintController rbcController) {
super(context);
+ mReduceBrightColorsTintController = rbcController;
mHandler = new TintHandler(DisplayThread.get().getLooper());
mVisibleBackgroundUsersEnabled = isVisibleBackgroundUsersEnabled();
mUserManager = UserManagerService.getInstance();
@@ -571,27 +576,37 @@ public final class ColorDisplayService extends SystemService {
return mColorModeCompositionColorSpaces.get(mode, Display.COLOR_MODE_INVALID);
}
- private void onDisplayColorModeChanged(int mode) {
+ @VisibleForTesting
+ void onDisplayColorModeChanged(int mode) {
if (mode == NOT_SET) {
return;
}
+ mReduceBrightColorsTintController.cancelAnimator();
mNightDisplayTintController.cancelAnimator();
mDisplayWhiteBalanceTintController.cancelAnimator();
+ final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
+
if (mNightDisplayTintController.isAvailable(getContext())) {
- final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
mNightDisplayTintController.setUp(getContext(), dtm.needsLinearColorMatrix(mode));
mNightDisplayTintController
.setMatrix(mNightDisplayTintController.getColorTemperatureSetting());
}
+ if (mReduceBrightColorsTintController.isAvailable(getContext())) {
+ // Different color modes may require different coefficients to be loaded for RBC.
+ // Re-set up RBC so that it can recalculate its transform matrix with new values.
+ mReduceBrightColorsTintController.setUp(getContext(), dtm.needsLinearColorMatrix(mode));
+ onReduceBrightColorsStrengthLevelChanged(); // Trigger matrix recalc + updates
+ }
+
// dtm.setColorMode() needs to be called before
// updateDisplayWhiteBalanceStatus(), this is because the latter calls
// DisplayTransformManager.needsLinearColorMatrix(), therefore it is dependent
// on the state of DisplayTransformManager.
- final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
dtm.setColorMode(mode, mNightDisplayTintController.getMatrix(),
+ mReduceBrightColorsTintController.getMatrix(),
getCompositionColorSpace(mode));
if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
diff --git a/services/core/java/com/android/server/display/color/DisplayTransformManager.java b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
index a76c427bec0e..cb7b1773e47e 100644
--- a/services/core/java/com/android/server/display/color/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
@@ -265,7 +265,7 @@ public class DisplayTransformManager {
/**
* Sets color mode and updates night display transform values.
*/
- public boolean setColorMode(int colorMode, float[] nightDisplayMatrix,
+ public boolean setColorMode(int colorMode, float[] nightDisplayMatrix, float[] rbcMatrix,
int compositionColorMode) {
if (colorMode == ColorDisplayManager.COLOR_MODE_NATURAL) {
applySaturation(COLOR_SATURATION_NATURAL);
@@ -285,7 +285,11 @@ public class DisplayTransformManager {
setDisplayColor(colorMode, compositionColorMode);
}
+ // These are close to the setDisplayColor() call to reduce delay between
+ // setting these matrixes and updating the color mode. Without this proximity
+ // of calls, updates to color mode can result in flicker.
setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, nightDisplayMatrix);
+ setColorMatrix(LEVEL_COLOR_MATRIX_REDUCE_BRIGHT_COLORS, rbcMatrix);
updateConfiguration();
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index 78bd41bd2e11..85b6bbb40b91 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -46,10 +46,6 @@ public class DisplayManagerFlags {
Flags.FLAG_ENABLE_CONNECTED_DISPLAY_MANAGEMENT,
Flags::enableConnectedDisplayManagement);
- private final FlagState mNbmControllerFlagState = new FlagState(
- Flags.FLAG_ENABLE_NBM_CONTROLLER,
- Flags::enableNbmController);
-
private final FlagState mHdrClamperFlagState = new FlagState(
Flags.FLAG_ENABLE_HDR_CLAMPER,
Flags::enableHdrClamper);
@@ -282,11 +278,6 @@ public class DisplayManagerFlags {
return mConnectedDisplayManagementFlagState.isEnabled();
}
- /** Returns whether NBM Controller is enabled or not. */
- public boolean isNbmControllerEnabled() {
- return mNbmControllerFlagState.isEnabled();
- }
-
/** Returns whether hdr clamper is enabled on not. */
public boolean isHdrClamperEnabled() {
return mHdrClamperFlagState.isEnabled();
@@ -595,7 +586,6 @@ public class DisplayManagerFlags {
pw.println(" " + mExternalDisplayLimitModeState);
pw.println(" " + mDisplayTopology);
pw.println(" " + mHdrClamperFlagState);
- pw.println(" " + mNbmControllerFlagState);
pw.println(" " + mPowerThrottlingClamperFlagState);
pw.println(" " + mEvenDimmerFlagState);
pw.println(" " + mSmallAreaDetectionFlagState);
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 123b7dfbf843..3358f723709c 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -37,14 +37,6 @@ flag {
}
flag {
- name: "enable_nbm_controller"
- namespace: "display_manager"
- description: "Feature flag for Normal Brightness Mode Controller"
- bug: "299527549"
- is_fixed_read_only: true
-}
-
-flag {
name: "enable_hdr_clamper"
namespace: "display_manager"
description: "Feature flag for HDR Clamper"
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index d8c35358102d..f09be2c15ee0 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -289,7 +289,9 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider {
// doesn't have any registered discovery preference, we should still be able to route their
// system media.
boolean bindDueToSystemMediaRoutingSupport =
- mIsManagerScanning && mSupportsSystemMediaRouting;
+ mLastDiscoveryPreference != null
+ && mLastDiscoveryPreference.shouldPerformActiveScan()
+ && mSupportsSystemMediaRouting;
if (!getSessionInfos().isEmpty()
|| bindDueToManagerScan
|| bindDueToSystemMediaRoutingSupport) {
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
index 69c460e0f19d..42303e042561 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
@@ -32,6 +32,7 @@ import android.content.pm.ServiceInfo;
import android.media.MediaRoute2ProviderService;
import android.os.Handler;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
@@ -162,8 +163,14 @@ final class MediaRoute2ProviderWatcher {
mUserId);
Slog.i(
TAG,
- "Enabling proxy for MediaRoute2ProviderService: "
- + proxy.mComponentName);
+ TextUtils.formatSimple(
+ "Enabling proxy for MediaRoute2ProviderService: %s"
+ + " (isSelfScan=%b, supportsSystemMediaRouting=%b,"
+ + " userId=%d)",
+ proxy.mComponentName,
+ isSelfScanOnlyProvider,
+ supportsSystemMediaRouting,
+ mUserId));
proxy.start(/* rebindIfDisconnected= */ false);
mProxies.add(targetIndex++, proxy);
mCallback.onAddProviderService(proxy);
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index e18ed410c045..58deffcbd4ba 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -848,7 +848,7 @@ class MediaRouter2ServiceImpl {
UserRecord userRecord = getOrCreateUserRecordLocked(userId);
List<RoutingSessionInfo> sessionInfos;
if (hasSystemRoutingPermissions) {
- if (setDeviceRouteSelected) {
+ if (setDeviceRouteSelected && !Flags.enableMirroringInMediaRouter2()) {
// Return a fake system session that shows the device route as selected and
// available bluetooth routes as transferable.
return userRecord.mHandler.getSystemProvider()
@@ -2733,6 +2733,15 @@ class MediaRouter2ServiceImpl {
newRoutes = Collections.emptySet();
}
+ if (Flags.enableMirroringInMediaRouter2()
+ && provider instanceof MediaRoute2ProviderServiceProxy proxyProvider) {
+ // We notify the system provider of service updates, so that it can update the
+ // system routing session by adding them as transferable routes. And we remove those
+ // that don't support remote routing.
+ mSystemProvider.updateSystemMediaRoutesFromProxy(proxyProvider);
+ newRoutes.removeIf(it -> !it.supportsRemoteRouting());
+ }
+
// Add new routes to the maps.
ArrayList<MediaRoute2Info> addedRoutes = new ArrayList<>();
boolean hasAddedOrModifiedRoutes = false;
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index 8dfba39dcfd8..b93846bf9ee7 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -73,6 +73,10 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
// For apps without MODIFYING_AUDIO_ROUTING permission.
// This should be the currently selected route.
MediaRoute2Info mDefaultRoute;
+
+ @GuardedBy("mLock")
+ RoutingSessionInfo mSystemSessionInfo;
+
RoutingSessionInfo mDefaultSessionInfo;
private final AudioManagerBroadcastReceiver mAudioReceiver =
@@ -180,7 +184,10 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
if (TextUtils.equals(routeOriginalId, mSelectedRouteId)) {
RoutingSessionInfo currentSessionInfo;
synchronized (mLock) {
- currentSessionInfo = mSessionInfos.get(0);
+ currentSessionInfo =
+ Flags.enableMirroringInMediaRouter2()
+ ? mSystemSessionInfo
+ : mSessionInfos.get(0);
}
mCallback.onSessionCreated(this, requestId, currentSessionInfo);
return;
@@ -354,7 +361,10 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
}
if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) {
- RoutingSessionInfo oldSessionInfo = mSessionInfos.get(0);
+ var oldSessionInfo =
+ Flags.enableMirroringInMediaRouter2()
+ ? mSystemSessionInfo
+ : mSessionInfos.get(0);
builder.setTransferReason(oldSessionInfo.getTransferReason())
.setTransferInitiator(oldSessionInfo.getTransferInitiatorUserHandle(),
oldSessionInfo.getTransferInitiatorPackageName());
@@ -364,6 +374,31 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
}
}
+ /**
+ * Notifies the system provider of a {@link MediaRoute2ProviderServiceProxy} update.
+ *
+ * <p>To be overridden so as to generate system media routes for {@link
+ * MediaRoute2ProviderService} routes that {@link MediaRoute2Info#supportsSystemMediaRouting()
+ * support system media routing}).
+ *
+ * @param serviceProxy The proxy of the service that updated its state.
+ */
+ public void updateSystemMediaRoutesFromProxy(MediaRoute2ProviderServiceProxy serviceProxy) {
+ // Do nothing. This implementation doesn't support MR2ProviderService system media routes.
+ // The subclass overrides this method to implement app-managed system media routing (aka
+ // mirroring).
+ }
+
+ /**
+ * Called when the system provider state changes.
+ *
+ * <p>To be overridden by {@link SystemMediaRoute2Provider2}, so that app-provided system media
+ * routing routes are added before setting the provider state.
+ */
+ public void onSystemProviderRoutesChanged(MediaRoute2ProviderInfo providerInfo) {
+ setProviderState(providerInfo);
+ }
+
protected void updateProviderState() {
MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder();
@@ -373,7 +408,9 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
for (MediaRoute2Info route : deviceRoutes) {
builder.addRoute(route);
}
- setProviderState(builder.build());
+ if (!Flags.enableMirroringInMediaRouter2()) {
+ setProviderState(builder.build());
+ }
} else {
builder.addRoute(mDeviceRouteController.getSelectedRoute());
}
@@ -382,7 +419,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
builder.addRoute(route);
}
MediaRoute2ProviderInfo providerInfo = builder.build();
- setProviderState(providerInfo);
+ onSystemProviderRoutesChanged(providerInfo);
if (DEBUG) {
Slog.d(TAG, "Updating system provider info : " + providerInfo);
}
@@ -393,8 +430,12 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
*/
boolean updateSessionInfosIfNeeded() {
synchronized (mLock) {
- RoutingSessionInfo oldSessionInfo = mSessionInfos.isEmpty() ? null : mSessionInfos.get(
- 0);
+ RoutingSessionInfo oldSessionInfo;
+ if (Flags.enableMirroringInMediaRouter2()) {
+ oldSessionInfo = mSystemSessionInfo;
+ } else {
+ oldSessionInfo = mSessionInfos.isEmpty() ? null : mSessionInfos.get(0);
+ }
RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder(
SYSTEM_SESSION_ID, "" /* clientPackageName */)
@@ -483,8 +524,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
if (DEBUG) {
Slog.d(TAG, "Updating system routing session info : " + newSessionInfo);
}
- mSessionInfos.clear();
- mSessionInfos.add(newSessionInfo);
+ mSystemSessionInfo = newSessionInfo;
+ onSystemSessionInfoUpdated();
mDefaultSessionInfo =
new RoutingSessionInfo.Builder(
SYSTEM_SESSION_ID, "" /* clientPackageName */)
@@ -501,6 +542,12 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
}
}
+ @GuardedBy("mLock")
+ protected void onSystemSessionInfoUpdated() {
+ mSessionInfos.clear();
+ mSessionInfos.add(mSystemSessionInfo);
+ }
+
@GuardedBy("mRequestLock")
private void reportPendingSessionRequestResultLockedIfNeeded(
RoutingSessionInfo newSessionInfo) {
@@ -587,6 +634,9 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
RoutingSessionInfo sessionInfo;
synchronized (mLock) {
sessionInfo = mSessionInfos.get(0);
+ if (sessionInfo == null) {
+ return;
+ }
}
mCallback.onSessionUpdated(this, sessionInfo);
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java
index 85b30ad8cadb..7dc30ab66fd2 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider2.java
@@ -16,11 +16,26 @@
package com.android.server.media;
+import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO;
+
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
+import android.media.MediaRoute2Info;
+import android.media.MediaRoute2ProviderInfo;
import android.media.MediaRoute2ProviderService;
+import android.media.RoutingSessionInfo;
import android.os.Looper;
import android.os.UserHandle;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Stream;
/**
* Extends {@link SystemMediaRoute2Provider} by adding system routes provided by {@link
@@ -30,6 +45,15 @@ import android.os.UserHandle;
*/
/* package */ class SystemMediaRoute2Provider2 extends SystemMediaRoute2Provider {
+ private static final String ROUTE_ID_PREFIX_SYSTEM = "SYSTEM";
+ private static final String ROUTE_ID_SYSTEM_SEPARATOR = ".";
+
+ @GuardedBy("mLock")
+ private MediaRoute2ProviderInfo mLastSystemProviderInfo;
+
+ @GuardedBy("mLock")
+ private final Map<String, ProviderProxyRecord> mProxyRecords = new HashMap<>();
+
private static final ComponentName COMPONENT_NAME =
new ComponentName(
SystemMediaRoute2Provider2.class.getPackage().getName(),
@@ -46,4 +70,117 @@ import android.os.UserHandle;
private SystemMediaRoute2Provider2(Context context, UserHandle user, Looper looper) {
super(context, COMPONENT_NAME, user, looper);
}
+
+ @Override
+ protected void onSystemSessionInfoUpdated() {
+ updateSessionInfo();
+ }
+
+ @Override
+ public void updateSystemMediaRoutesFromProxy(MediaRoute2ProviderServiceProxy serviceProxy) {
+ var proxyRecord = ProviderProxyRecord.createFor(serviceProxy);
+ synchronized (mLock) {
+ if (proxyRecord == null) {
+ mProxyRecords.remove(serviceProxy.mUniqueId);
+ } else {
+ mProxyRecords.put(serviceProxy.mUniqueId, proxyRecord);
+ }
+ setProviderState(buildProviderInfo());
+ }
+ updateSessionInfo();
+ notifyProviderState();
+ notifySessionInfoUpdated();
+ }
+
+ @Override
+ public void onSystemProviderRoutesChanged(MediaRoute2ProviderInfo providerInfo) {
+ synchronized (mLock) {
+ mLastSystemProviderInfo = providerInfo;
+ setProviderState(buildProviderInfo());
+ }
+ updateSessionInfo();
+ notifySessionInfoUpdated();
+ }
+
+ /**
+ * Updates the {@link #mSessionInfos} by expanding the {@link SystemMediaRoute2Provider} session
+ * with information from the {@link MediaRoute2ProviderService provider services}.
+ */
+ private void updateSessionInfo() {
+ synchronized (mLock) {
+ var systemSessionInfo = mSystemSessionInfo;
+ if (systemSessionInfo == null) {
+ // The system session info hasn't been initialized yet. Do nothing.
+ return;
+ }
+ var builder = new RoutingSessionInfo.Builder(systemSessionInfo);
+ mProxyRecords.values().stream()
+ .flatMap(ProviderProxyRecord::getRoutesStream)
+ .map(MediaRoute2Info::getId)
+ .forEach(builder::addTransferableRoute);
+ mSessionInfos.clear();
+ mSessionInfos.add(builder.build());
+ }
+ }
+
+ /**
+ * Returns a new a provider info that includes all routes from the system provider {@link
+ * SystemMediaRoute2Provider}, along with system routes from {@link MediaRoute2ProviderService
+ * provider services}.
+ */
+ @GuardedBy("mLock")
+ private MediaRoute2ProviderInfo buildProviderInfo() {
+ MediaRoute2ProviderInfo.Builder builder =
+ new MediaRoute2ProviderInfo.Builder(mLastSystemProviderInfo);
+ mProxyRecords.values().stream()
+ .flatMap(ProviderProxyRecord::getRoutesStream)
+ .forEach(builder::addRoute);
+ return builder.build();
+ }
+
+ /**
+ * Holds information about {@link MediaRoute2ProviderService provider services} registered in
+ * the system.
+ *
+ * @param mProxy The corresponding {@link MediaRoute2ProviderServiceProxy}.
+ * @param mSystemMediaRoutes The last snapshot of routes from the service that support system
+ * media routing, as defined by {@link MediaRoute2Info#supportsSystemMediaRouting()}.
+ */
+ private record ProviderProxyRecord(
+ MediaRoute2ProviderServiceProxy mProxy,
+ Collection<MediaRoute2Info> mSystemMediaRoutes) {
+
+ /** Returns a stream representation of the {@link #mSystemMediaRoutes}. */
+ public Stream<MediaRoute2Info> getRoutesStream() {
+ return mSystemMediaRoutes.stream();
+ }
+
+ /**
+ * Returns a new instance, or null if the given {@code serviceProxy} doesn't have an
+ * associated {@link MediaRoute2ProviderInfo}.
+ */
+ @Nullable
+ public static ProviderProxyRecord createFor(MediaRoute2ProviderServiceProxy serviceProxy) {
+ MediaRoute2ProviderInfo providerInfo = serviceProxy.getProviderInfo();
+ if (providerInfo == null) {
+ return null;
+ }
+ ArraySet<MediaRoute2Info> routes = new ArraySet<>();
+ providerInfo.getRoutes().stream()
+ .filter(MediaRoute2Info::supportsSystemMediaRouting)
+ .forEach(
+ route -> {
+ String id =
+ ROUTE_ID_PREFIX_SYSTEM
+ + route.getProviderId()
+ + ROUTE_ID_SYSTEM_SEPARATOR
+ + route.getOriginalId();
+ routes.add(
+ new MediaRoute2Info.Builder(id, route.getName())
+ .addFeature(FEATURE_LIVE_AUDIO)
+ .build());
+ });
+ return new ProviderProxyRecord(serviceProxy, Collections.unmodifiableSet(routes));
+ }
+ }
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 95aff5652bb6..b571d62c0cba 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -1554,15 +1554,18 @@ public class ZenModeHelper {
if (isFromApp) {
// Don't allow apps to toggle hidden (non-public-API) effects.
- newEffects = new ZenDeviceEffects.Builder(newEffects)
- .setShouldDisableAutoBrightness(oldEffects.shouldDisableAutoBrightness())
- .setShouldDisableTapToWake(oldEffects.shouldDisableTapToWake())
- .setShouldDisableTiltToWake(oldEffects.shouldDisableTiltToWake())
- .setShouldDisableTouch(oldEffects.shouldDisableTouch())
- .setShouldMinimizeRadioUsage(oldEffects.shouldMinimizeRadioUsage())
- .setShouldMaximizeDoze(oldEffects.shouldMaximizeDoze())
- .setExtraEffects(oldEffects.getExtraEffects())
- .build();
+ newEffects =
+ new ZenDeviceEffects.Builder(newEffects)
+ .setShouldDisableAutoBrightness(
+ oldEffects.shouldDisableAutoBrightness())
+ .setShouldDisableTapToWake(oldEffects.shouldDisableTapToWake())
+ .setShouldDisableTiltToWake(oldEffects.shouldDisableTiltToWake())
+ .setShouldDisableTouch(oldEffects.shouldDisableTouch())
+ .setShouldMinimizeRadioUsage(oldEffects.shouldMinimizeRadioUsage())
+ .setShouldMaximizeDoze(oldEffects.shouldMaximizeDoze())
+ .setShouldUseNightLight(oldEffects.shouldUseNightLight())
+ .setExtraEffects(oldEffects.getExtraEffects())
+ .build();
}
zenRule.zenDeviceEffects = newEffects;
@@ -1601,6 +1604,9 @@ public class ZenModeHelper {
if (oldEffects.shouldMaximizeDoze() != newEffects.shouldMaximizeDoze()) {
userModifiedFields |= ZenDeviceEffects.FIELD_MAXIMIZE_DOZE;
}
+ if (oldEffects.shouldUseNightLight() != newEffects.shouldUseNightLight()) {
+ userModifiedFields |= ZenDeviceEffects.FIELD_NIGHT_LIGHT;
+ }
if (!Objects.equals(oldEffects.getExtraEffects(), newEffects.getExtraEffects())) {
userModifiedFields |= ZenDeviceEffects.FIELD_EXTRA_EFFECTS;
}
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index 137ea0617f21..7c7504dccf94 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -80,6 +80,7 @@ import com.android.server.utils.Slogf;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -296,11 +297,7 @@ public final class HintManagerService extends SystemService {
mPowerHalVersion = 0;
mUsesFmq = false;
if (mPowerHal != null) {
- try {
- mSupportInfo = getSupportInfo();
- } catch (RemoteException e) {
- throw new IllegalStateException("Could not contact PowerHAL!", e);
- }
+ mSupportInfo = getSupportInfo();
}
mDefaultCpuHeadroomCalculationWindowMillis =
new CpuHeadroomParamsInternal().calculationWindowMillis;
@@ -318,7 +315,7 @@ public final class HintManagerService extends SystemService {
}
}
- SupportInfo getSupportInfo() throws RemoteException {
+ SupportInfo getSupportInfo() {
try {
mPowerHalVersion = mPowerHal.getInterfaceVersion();
if (mPowerHalVersion >= 6) {
@@ -329,40 +326,9 @@ public final class HintManagerService extends SystemService {
}
SupportInfo supportInfo = new SupportInfo();
- supportInfo.usesSessions = isHintSessionSupported();
- // Global boosts & modes aren't currently relevant for HMS clients
- supportInfo.boosts = 0;
- supportInfo.modes = 0;
- supportInfo.sessionHints = 0;
- supportInfo.sessionModes = 0;
- supportInfo.sessionTags = 0;
-
supportInfo.headroom = new SupportInfo.HeadroomSupportInfo();
supportInfo.headroom.isCpuSupported = false;
supportInfo.headroom.isGpuSupported = false;
- if (isHintSessionSupported()) {
- if (mPowerHalVersion == 4) {
- // Assume we support the V4 hints & modes unless specified
- // otherwise; this is to avoid breaking backwards compat
- // since we historically just assumed they were.
- supportInfo.sessionHints = 31; // first 5 bits are ones
- }
- if (mPowerHalVersion == 5) {
- // Assume we support the V5 hints & modes unless specified
- // otherwise; this is to avoid breaking backwards compat
- // since we historically just assumed they were.
-
- // Hal V5 has 8 modes, all of which it assumes are supported,
- // so we represent that by having the first 8 bits set
- supportInfo.sessionHints = 255; // first 8 bits are ones
- // Hal V5 has 1 mode which it assumes is supported, so we
- // represent that by having the first bit set
- supportInfo.sessionModes = 1;
- // Hal V5 has 5 tags, all of which it assumes are supported,
- // so we represent that by having the first 5 bits set
- supportInfo.sessionTags = 31;
- }
- }
return supportInfo;
}
@@ -1263,7 +1229,7 @@ public final class HintManagerService extends SystemService {
@SessionTag int tag, SessionCreationConfig creationConfig,
SessionConfig config) {
if (!isHintSessionSupported()) {
- throw new UnsupportedOperationException("PowerHintSessions are not supported!");
+ throw new UnsupportedOperationException("PowerHAL is not supported!");
}
java.util.Objects.requireNonNull(token);
@@ -1459,6 +1425,12 @@ public final class HintManagerService extends SystemService {
removeChannelItem(callingTgid, callingUid);
};
+ @Override
+ public long getHintSessionPreferredRate() {
+ return mHintSessionPreferredRate;
+ }
+
+ @Override
public int getMaxGraphicsPipelineThreadsCount() {
return MAX_GRAPHICS_PIPELINE_THREADS_COUNT;
}
@@ -1480,6 +1452,7 @@ public final class HintManagerService extends SystemService {
if (!mSupportInfo.headroom.isCpuSupported) {
throw new UnsupportedOperationException();
}
+ checkCpuHeadroomParams(params);
final CpuHeadroomParams halParams = new CpuHeadroomParams();
halParams.tids = new int[]{Binder.getCallingPid()};
halParams.calculationType = params.calculationType;
@@ -1487,10 +1460,6 @@ public final class HintManagerService extends SystemService {
if (params.usesDeviceHeadroom) {
halParams.tids = new int[]{};
} else if (params.tids != null && params.tids.length > 0) {
- if (params.tids.length > 5) {
- throw new IllegalArgumentException(
- "More than 5 TIDs is requested: " + params.tids.length);
- }
if (SystemProperties.getBoolean(PROPERTY_CHECK_HEADROOM_TID, true)) {
final int tgid = Process.getThreadGroupLeader(Binder.getCallingPid());
for (int tid : params.tids) {
@@ -1530,11 +1499,45 @@ public final class HintManagerService extends SystemService {
}
}
+ private void checkCpuHeadroomParams(CpuHeadroomParamsInternal params) {
+ boolean calculationTypeMatched = false;
+ try {
+ for (final Field field :
+ CpuHeadroomParams.CalculationType.class.getDeclaredFields()) {
+ if (field.getType() == byte.class) {
+ byte value = field.getByte(null);
+ if (value == params.calculationType) {
+ calculationTypeMatched = true;
+ break;
+ }
+ }
+ }
+ } catch (IllegalAccessException e) {
+ Slog.wtf(TAG, "Checking the calculation type was unexpectedly not allowed");
+ }
+ if (!calculationTypeMatched) {
+ throw new IllegalArgumentException(
+ "Unknown CPU headroom calculation type " + (int) params.calculationType);
+ }
+ if (params.calculationWindowMillis < 50 || params.calculationWindowMillis > 10000) {
+ throw new IllegalArgumentException(
+ "Invalid CPU headroom calculation window, expected [50, 10000] but got "
+ + params.calculationWindowMillis);
+ }
+ if (!params.usesDeviceHeadroom) {
+ if (params.tids != null && params.tids.length > 5) {
+ throw new IllegalArgumentException(
+ "More than 5 TIDs requested: " + params.tids.length);
+ }
+ }
+ }
+
@Override
public GpuHeadroomResult getGpuHeadroom(@NonNull GpuHeadroomParamsInternal params) {
if (!mSupportInfo.headroom.isGpuSupported) {
throw new UnsupportedOperationException();
}
+ checkGpuHeadroomParams(params);
final GpuHeadroomParams halParams = new GpuHeadroomParams();
halParams.calculationType = params.calculationType;
halParams.calculationWindowMillis = params.calculationWindowMillis;
@@ -1565,6 +1568,33 @@ public final class HintManagerService extends SystemService {
}
}
+ private void checkGpuHeadroomParams(GpuHeadroomParamsInternal params) {
+ boolean calculationTypeMatched = false;
+ try {
+ for (final Field field :
+ GpuHeadroomParams.CalculationType.class.getDeclaredFields()) {
+ if (field.getType() == byte.class) {
+ byte value = field.getByte(null);
+ if (value == params.calculationType) {
+ calculationTypeMatched = true;
+ break;
+ }
+ }
+ }
+ } catch (IllegalAccessException e) {
+ Slog.wtf(TAG, "Checking the calculation type was unexpectedly not allowed");
+ }
+ if (!calculationTypeMatched) {
+ throw new IllegalArgumentException(
+ "Unknown GPU headroom calculation type " + (int) params.calculationType);
+ }
+ if (params.calculationWindowMillis < 50 || params.calculationWindowMillis > 10000) {
+ throw new IllegalArgumentException(
+ "Invalid GPU headroom calculation window, expected [50, 10000] but got "
+ + params.calculationWindowMillis);
+ }
+ }
+
@Override
public long getCpuHeadroomMinIntervalMillis() {
if (!mSupportInfo.headroom.isCpuSupported) {
@@ -1590,16 +1620,6 @@ public final class HintManagerService extends SystemService {
mSessionManager = ISessionManager.Stub.asInterface(sessionManager);
}
- public IHintManager.HintManagerClientData
- registerClient(@NonNull IHintManager.IHintManagerClient clientBinder) {
- IHintManager.HintManagerClientData out = new IHintManager.HintManagerClientData();
- out.preferredRateNanos = mHintSessionPreferredRate;
- out.maxGraphicsPipelineThreads = getMaxGraphicsPipelineThreadsCount();
- out.powerHalVersion = mPowerHalVersion;
- out.supportInfo = mSupportInfo;
- return out;
- }
-
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
@@ -1607,7 +1627,7 @@ public final class HintManagerService extends SystemService {
}
pw.println("HintSessionPreferredRate: " + mHintSessionPreferredRate);
pw.println("MaxGraphicsPipelineThreadsCount: " + MAX_GRAPHICS_PIPELINE_THREADS_COUNT);
- pw.println("Hint Session Support: " + isHintSessionSupported());
+ pw.println("HAL Support: " + isHintSessionSupported());
pw.println("Active Sessions:");
synchronized (mLock) {
for (int i = 0; i < mActiveSessions.size(); i++) {
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 24a6f118ad04..4bcba13448e9 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -258,16 +258,13 @@ class InsetsPolicy {
* We also need to exclude certain types of insets source for client within specific windowing
* modes.
*
- * @param attrs the LayoutParams of the target
- * @param windowingMode the windowing mode of the target
- * @param isAlwaysOnTop is the target always on top
+ * @param target the target on which the policy is applied
* @param state the input inset state containing all the sources
* @return The state stripped of the necessary information.
*/
- InsetsState enforceInsetsPolicyForTarget(WindowManager.LayoutParams attrs,
- @WindowConfiguration.WindowingMode int windowingMode, boolean isAlwaysOnTop,
- InsetsState state) {
+ InsetsState enforceInsetsPolicyForTarget(WindowState target, InsetsState state) {
final InsetsState originalState = state;
+ final WindowManager.LayoutParams attrs = target.getAttrs();
// The caller should not receive the visible insets provided by itself.
if (attrs.type == TYPE_INPUT_METHOD) {
@@ -316,12 +313,17 @@ class InsetsPolicy {
}
}
+ final @WindowConfiguration.WindowingMode int windowingMode = target.getWindowingMode();
if (WindowConfiguration.isFloating(windowingMode)
- || (windowingMode == WINDOWING_MODE_MULTI_WINDOW && isAlwaysOnTop)) {
+ || (windowingMode == WINDOWING_MODE_MULTI_WINDOW && target.isAlwaysOnTop())) {
// Keep frames, caption, and IME.
int types = WindowInsets.Type.captionBar();
if (windowingMode != WINDOWING_MODE_PINNED) {
- types |= WindowInsets.Type.ime();
+ if (!Flags.refactorInsetsController() || (mDisplayContent != null
+ && target == mDisplayContent.getImeInputTarget()
+ && (WindowInsets.Type.ime() & target.getRequestedVisibleTypes()) != 0)) {
+ types |= WindowInsets.Type.ime();
+ }
}
final InsetsState newState = new InsetsState();
newState.set(state, types);
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index bcd12f253299..b4a22b0dd034 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -4150,7 +4150,9 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
.setSourceCrop(cropBounds)
.setCaptureSecureLayers(true)
.setAllowProtected(true)
- .setHintForSeamlessTransition(isDisplayRotation)
+ // We always reroute this screenshot to the display, so this transition
+ // is ALWAYS seamless
+ .setHintForSeamlessTransition(true)
.build();
ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
ScreenCapture.captureLayers(captureArgs);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 90bf053dfbef..68b4b6f0ae91 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1631,8 +1631,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
final InsetsState rawInsetsState =
mFrozenInsetsState != null ? mFrozenInsetsState : getMergedInsetsState();
- final InsetsState insetsStateForWindow = insetsPolicy.enforceInsetsPolicyForTarget(
- mAttrs, getWindowingMode(), isAlwaysOnTop(), rawInsetsState);
+ final InsetsState insetsStateForWindow = insetsPolicy.enforceInsetsPolicyForTarget(this,
+ rawInsetsState);
return insetsPolicy.adjustInsetsForWindow(this, insetsStateForWindow,
includeTransient);
}
@@ -3303,7 +3303,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// just kill it. And if it is a window of foreground activity, the activity can be
// restarted automatically if needed.
Slog.w(TAG, "Exception thrown during dispatchAppVisibility " + this, e);
- if (android.os.Process.getUidForPid(mSession.mPid) == mSession.mUid) {
+ if (android.os.Process.getUidForPid(mSession.mPid) == mSession.mUid
+ && android.os.Process.getThreadGroupLeader(mSession.mPid) == mSession.mPid) {
android.os.Process.killProcess(mSession.mPid);
}
}
diff --git a/services/supervision/java/com/android/server/supervision/SupervisionService.java b/services/supervision/java/com/android/server/supervision/SupervisionService.java
index 0ccaa6043f5f..073ee31ddd60 100644
--- a/services/supervision/java/com/android/server/supervision/SupervisionService.java
+++ b/services/supervision/java/com/android/server/supervision/SupervisionService.java
@@ -16,6 +16,11 @@
package com.android.server.supervision;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import static com.android.internal.util.Preconditions.checkCallAuthorization;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -31,6 +36,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.os.Binder;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -78,6 +84,9 @@ public class SupervisionService extends ISupervisionManager.Stub {
@Override
public boolean isSupervisionEnabledForUser(@UserIdInt int userId) {
+ if (UserHandle.getUserId(Binder.getCallingUid()) != userId) {
+ enforcePermission(INTERACT_ACROSS_USERS);
+ }
synchronized (getLockObject()) {
return getUserDataLocked(userId).supervisionEnabled;
}
@@ -151,7 +160,8 @@ public class SupervisionService extends ISupervisionManager.Stub {
/** Returns whether the supervision app has profile owner status. */
private boolean isProfileOwner(@UserIdInt int userId) {
- ComponentName profileOwner = mDpmInternal.getProfileOwnerAsUser(userId);
+ ComponentName profileOwner =
+ mDpmInternal != null ? mDpmInternal.getProfileOwnerAsUser(userId) : null;
return profileOwner != null && isSupervisionAppPackage(profileOwner.getPackageName());
}
@@ -161,6 +171,12 @@ public class SupervisionService extends ISupervisionManager.Stub {
mContext.getResources().getString(R.string.config_systemSupervision));
}
+ /** Enforces that the caller has the given permission. */
+ private void enforcePermission(String permission) {
+ checkCallAuthorization(
+ mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED);
+ }
+
public static class Lifecycle extends SystemService {
private final SupervisionService mSupervisionService;
diff --git a/services/tests/displayservicetests/src/com/android/server/display/BrightnessRangeControllerTest.kt b/services/tests/displayservicetests/src/com/android/server/display/BrightnessRangeControllerTest.kt
index f589a2c9385c..7db6ea0bf86d 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/BrightnessRangeControllerTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/BrightnessRangeControllerTest.kt
@@ -60,12 +60,6 @@ class BrightnessRangeControllerTest {
}
@Test
- fun testMaxBrightness_HbmDisabledAndNotAllowed() {
- val controller = createController(nbmEnabled = false, hbmAllowed = false)
- assertThat(controller.currentBrightnessMax).isEqualTo(MAX_BRIGHTNESS)
- }
-
- @Test
fun testMaxBrightness_transitionPointLessThanCurrentNbmLimit() {
val controller = createController(
hbmAllowed = false,
@@ -76,13 +70,11 @@ class BrightnessRangeControllerTest {
}
private fun createController(
- nbmEnabled: Boolean = true,
hbmSupported: Boolean = true,
hbmAllowed: Boolean = true,
hbmMaxBrightness: Float = MAX_BRIGHTNESS,
nbmMaxBrightness: Float = NORMAL_BRIGHTNESS_LOW
): BrightnessRangeController {
- whenever(mockFlags.isNbmControllerEnabled).thenReturn(nbmEnabled)
whenever(mockHbmController.deviceSupportsHbm()).thenReturn(hbmSupported)
whenever(mockHbmController.isHbmCurrentlyAllowed).thenReturn(hbmAllowed)
whenever(mockHbmController.currentBrightnessMax).thenReturn(hbmMaxBrightness)
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index 8ca39194de3b..a4dfecb8ed96 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -2626,8 +2626,8 @@ public final class DisplayPowerControllerTest {
mock(ScreenOffBrightnessSensorController.class);
final HighBrightnessModeController hbmController = mock(HighBrightnessModeController.class);
final HdrClamper hdrClamper = mock(HdrClamper.class);
- final NormalBrightnessModeController normalBrightnessModeController = mock(
- NormalBrightnessModeController.class);
+ final NormalBrightnessModeController normalBrightnessModeController =
+ new NormalBrightnessModeController();
BrightnessClamperController clamperController = mock(BrightnessClamperController.class);
when(hbmController.getCurrentBrightnessMax()).thenReturn(PowerManager.BRIGHTNESS_MAX);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessEventTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessEventTest.java
index df09b046ddd2..6d1e56d1f479 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessEventTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessEventTest.java
@@ -68,6 +68,8 @@ public final class BrightnessEventTest {
mBrightnessEvent.setAutomaticBrightnessEnabled(true);
mBrightnessEvent.setDisplayBrightnessStrategyName(DISPLAY_BRIGHTNESS_STRATEGY_NAME);
mBrightnessEvent.setAutoBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE);
+ mBrightnessEvent.setSlowChange(true);
+ mBrightnessEvent.setRampSpeed(0.3f);
}
@Test
@@ -88,7 +90,7 @@ public final class BrightnessEventTest {
+ "preLux=150.0, wasShortTermModelActive=true, autoBrightness=true (idle), "
+ "unclampedBrt=0.65, hbmMax=0.62, hbmMode=off, thrmMax=0.65, "
+ "rbcStrength=-1, powerFactor=0.2, physDisp=display_name(987654321), "
- + "logicalId=1";
+ + "logicalId=1, slowChange=true, rampSpeed=0.3";
assertEquals(expectedString, actualString);
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/color/ColorDisplayServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/color/ColorDisplayServiceTest.java
index f391e409a717..4e81b3530b62 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/color/ColorDisplayServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/color/ColorDisplayServiceTest.java
@@ -20,10 +20,13 @@ import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -89,6 +92,7 @@ public class ColorDisplayServiceTest {
private ColorDisplayService.BinderService mBinderService;
private Resources mResourcesSpy;
+ private ReduceBrightColorsTintController mRbcSpy;
private static final int[] MINIMAL_COLOR_MODES = new int[] {
ColorDisplayManager.COLOR_MODE_NATURAL,
@@ -135,7 +139,8 @@ public class ColorDisplayServiceTest {
mLocalServiceKeeperRule.overrideLocalService(
DisplayManagerInternal.class, mDisplayManagerInternal);
- mCds = new ColorDisplayService(mContext);
+ mRbcSpy = Mockito.spy(new ReduceBrightColorsTintController());
+ mCds = new ColorDisplayService(mContext, mRbcSpy);
mBinderService = mCds.new BinderService();
mLocalServiceKeeperRule.overrideLocalService(
ColorDisplayService.ColorDisplayServiceInternal.class,
@@ -1106,7 +1111,8 @@ public class ColorDisplayServiceTest {
setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
startService();
verify(mDisplayTransformManager).setColorMode(
- eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), eq(Display.COLOR_MODE_INVALID));
+ eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), any(),
+ eq(Display.COLOR_MODE_INVALID));
}
@Test
@@ -1124,7 +1130,8 @@ public class ColorDisplayServiceTest {
setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
startService();
verify(mDisplayTransformManager).setColorMode(
- eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), eq(Display.COLOR_MODE_INVALID));
+ eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), any(),
+ eq(Display.COLOR_MODE_INVALID));
}
@Test
@@ -1140,7 +1147,8 @@ public class ColorDisplayServiceTest {
setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
startService();
verify(mDisplayTransformManager).setColorMode(
- eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), eq(Display.COLOR_MODE_SRGB));
+ eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), any(),
+ eq(Display.COLOR_MODE_SRGB));
}
@Test
@@ -1156,7 +1164,8 @@ public class ColorDisplayServiceTest {
setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED);
startService();
verify(mDisplayTransformManager).setColorMode(
- eq(ColorDisplayManager.COLOR_MODE_BOOSTED), any(), eq(Display.COLOR_MODE_INVALID));
+ eq(ColorDisplayManager.COLOR_MODE_BOOSTED), any(), any(),
+ eq(Display.COLOR_MODE_INVALID));
}
@Test
@@ -1164,10 +1173,27 @@ public class ColorDisplayServiceTest {
when(mResourcesSpy.getIntArray(R.array.config_availableColorModes))
.thenReturn(new int[] {});
startService();
- verify(mDisplayTransformManager, never()).setColorMode(anyInt(), any(), anyInt());
+ verify(mDisplayTransformManager, never()).setColorMode(anyInt(), any(), any(), anyInt());
assertThat(mBinderService.getColorMode()).isEqualTo(-1);
}
+ @Test
+ public void ensureColorModeChangeTriggersRbcReload() {
+ // should set up RBC once at startup
+ startService();
+ reset(mRbcSpy);
+
+ // Make sure RBC is enabled and available for this test
+ doReturn(true).when(mRbcSpy).isAvailable(mContext);
+
+ // When Color Mode changes, RBC needs to re-setup
+ // onDisplayColorModeChanged cancels animations, and should be called in handler thread
+ mCds.mHandler.runWithScissors(
+ () -> mCds.onDisplayColorModeChanged(ColorDisplayManager.COLOR_MODE_NATURAL),
+ 1000);
+ verify(mRbcSpy, times(1)).setUp(eq(mContext), anyBoolean());
+ }
+
/**
* Configures Night display to use a custom schedule.
*
diff --git a/services/tests/displayservicetests/src/com/android/server/display/color/DisplayTransformManagerTest.java b/services/tests/displayservicetests/src/com/android/server/display/color/DisplayTransformManagerTest.java
index 27f87aae35bb..a7ef5e0afc0e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/color/DisplayTransformManagerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/color/DisplayTransformManagerTest.java
@@ -19,6 +19,7 @@ package com.android.server.display.color;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
+import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_REDUCE_BRIGHT_COLORS;
import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE;
import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_DISPLAY_COLOR;
import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_SATURATION;
@@ -51,12 +52,14 @@ public class DisplayTransformManagerTest {
private MockitoSession mSession;
private DisplayTransformManager mDtm;
private float[] mNightDisplayMatrix;
+ private float[] mRbcMatrix;
private HashMap<String, String> mSystemProperties;
@Before
public void setUp() {
mDtm = new DisplayTransformManager();
mNightDisplayMatrix = mDtm.getColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY);
+ mRbcMatrix = mDtm.getColorMatrix(LEVEL_COLOR_MATRIX_REDUCE_BRIGHT_COLORS);
mSession = ExtendedMockito.mockitoSession()
.initMocks(this)
@@ -81,7 +84,8 @@ public class DisplayTransformManagerTest {
@Test
public void setColorMode_natural() {
- mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix, -1);
+ mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix, mRbcMatrix,
+ Display.COLOR_MODE_INVALID);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
.isEqualTo("0" /* managed */);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
@@ -90,7 +94,8 @@ public class DisplayTransformManagerTest {
@Test
public void setColorMode_boosted() {
- mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED, mNightDisplayMatrix, -1);
+ mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED, mNightDisplayMatrix, mRbcMatrix,
+ Display.COLOR_MODE_INVALID);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
.isEqualTo("0" /* managed */);
@@ -100,7 +105,8 @@ public class DisplayTransformManagerTest {
@Test
public void setColorMode_saturated() {
- mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED, mNightDisplayMatrix, -1);
+ mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED, mNightDisplayMatrix, mRbcMatrix,
+ Display.COLOR_MODE_INVALID);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
.isEqualTo("1" /* unmanaged */);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
@@ -109,7 +115,8 @@ public class DisplayTransformManagerTest {
@Test
public void setColorMode_automatic() {
- mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC, mNightDisplayMatrix, -1);
+ mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC, mNightDisplayMatrix, mRbcMatrix,
+ Display.COLOR_MODE_INVALID);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
.isEqualTo("2" /* enhanced */);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
@@ -118,7 +125,7 @@ public class DisplayTransformManagerTest {
@Test
public void setColorMode_vendor() {
- mDtm.setColorMode(0x100, mNightDisplayMatrix, -1);
+ mDtm.setColorMode(0x100, mNightDisplayMatrix, mRbcMatrix, Display.COLOR_MODE_INVALID);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
.isEqualTo(Integer.toString(0x100) /* pass-through */);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
@@ -127,7 +134,7 @@ public class DisplayTransformManagerTest {
@Test
public void setColorMode_outOfBounds() {
- mDtm.setColorMode(0x50, mNightDisplayMatrix, -1);
+ mDtm.setColorMode(0x50, mNightDisplayMatrix, mRbcMatrix, Display.COLOR_MODE_INVALID);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
.isEqualTo(null);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
@@ -141,7 +148,7 @@ public class DisplayTransformManagerTest {
// Start with a known state, which we expect to remain unmodified
SystemProperties.set(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE, magicPropertyValue);
- mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix,
+ mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix, mRbcMatrix,
Display.COLOR_MODE_INVALID);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE))
.isEqualTo(magicPropertyValue);
@@ -155,7 +162,7 @@ public class DisplayTransformManagerTest {
// Start with a known state, which we expect to get modified
SystemProperties.set(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE, magicPropertyValue);
- mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix,
+ mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix, mRbcMatrix,
testPropertyValue);
assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE))
.isEqualTo(Integer.toString(testPropertyValue));
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 1efe4707fc11..9e96800ca2e9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -18,6 +18,7 @@ package com.android.server.am;
import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL;
import static android.app.ActivityManager.PROCESS_CAPABILITY_BFSL;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_CPU_TIME;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
@@ -40,6 +41,7 @@ import static android.app.ActivityManager.PROCESS_STATE_TOP_SLEEPING;
import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ACTIVITY;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_NONE;
+import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_SHORT_FGS_TIMEOUT;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -283,6 +285,15 @@ public class MockingOomAdjusterTests {
}
}
+ private static void assertNoCpuTime(ProcessRecord app) {
+ assertEquals(0, app.mState.getSetCapability() & PROCESS_CAPABILITY_CPU_TIME);
+ }
+
+ private static void assertCpuTime(ProcessRecord app) {
+ assertEquals(PROCESS_CAPABILITY_CPU_TIME,
+ app.mState.getSetCapability() & PROCESS_CAPABILITY_CPU_TIME);
+ }
+
private static void assertBfsl(ProcessRecord app) {
assertEquals(PROCESS_CAPABILITY_BFSL,
app.mState.getSetCapability() & PROCESS_CAPABILITY_BFSL);
@@ -661,6 +672,7 @@ public class MockingOomAdjusterTests {
// SHORT_SERVICE, timed out already.
s = ServiceRecord.newEmptyInstanceForTest(mService);
s.appInfo = new ApplicationInfo();
+
mProcessStateController.setStartRequested(s, true);
s.isForeground = true;
s.foregroundServiceType = FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
@@ -687,6 +699,51 @@ public class MockingOomAdjusterTests {
@SuppressWarnings("GuardedBy")
@Test
+ @EnableFlags(Flags.FLAG_USE_CPU_TIME_CAPABILITY)
+ public void testUpdateOomAdjFreezeState_bindingFromShortFgs() {
+ // Setting up a started short FGS within app1.
+ final ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(mService);
+ s.appInfo = new ApplicationInfo();
+ mProcessStateController.setStartRequested(s, true);
+ s.isForeground = true;
+ s.foregroundServiceType = FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
+ mProcessStateController.setShortFgsInfo(s, SystemClock.uptimeMillis());
+
+ final ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+ MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+ mProcessStateController.setHostProcess(s, app);
+ mProcessStateController.setHasForegroundServices(app.mServices, true,
+ FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
+ mProcessStateController.startService(app.mServices, s);
+ app.mState.setLastTopTime(SystemClock.uptimeMillis()
+ - mService.mConstants.TOP_TO_FGS_GRACE_DURATION);
+
+ final ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+ MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+ // App1 with short service binds to app2
+ bindService(app2, app, null, null, 0, mock(IBinder.class));
+
+ setProcessesToLru(app, app2);
+ updateOomAdj(app);
+
+ assertCpuTime(app);
+ assertCpuTime(app2);
+
+ // Timeout the short FGS.
+ mProcessStateController.setShortFgsInfo(s, SystemClock.uptimeMillis()
+ - mService.mConstants.mShortFgsTimeoutDuration
+ - mService.mConstants.mShortFgsProcStateExtraWaitDuration);
+ mService.mServices.onShortFgsProcstateTimeout(s);
+ // mService is a mock, but this verifies that the timeout would trigger an update.
+ verify(mService).updateOomAdjLocked(app, OOM_ADJ_REASON_SHORT_FGS_TIMEOUT);
+ updateOomAdj(app);
+
+ assertNoCpuTime(app);
+ assertNoCpuTime(app2);
+ }
+
+ @SuppressWarnings("GuardedBy")
+ @Test
public void testUpdateOomAdj_DoOne_OverlayUi() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
@@ -3142,11 +3199,19 @@ public class MockingOomAdjusterTests {
assertEquals(true, app.getUidRecord().isSetAllowListed());
assertFreezeState(app, false);
assertFreezeState(app2, false);
+ if (Flags.useCpuTimeCapability()) {
+ assertCpuTime(app);
+ assertCpuTime(app2);
+ }
mProcessStateController.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
assertEquals(false, app.getUidRecord().isSetAllowListed());
assertFreezeState(app, true);
assertFreezeState(app2, true);
+ if (Flags.useCpuTimeCapability()) {
+ assertNoCpuTime(app);
+ assertNoCpuTime(app2);
+ }
}
@SuppressWarnings("GuardedBy")
@@ -3171,6 +3236,11 @@ public class MockingOomAdjusterTests {
assertFreezeState(app, false);
assertFreezeState(app2, false);
assertFreezeState(app3, false);
+ if (Flags.useCpuTimeCapability()) {
+ assertCpuTime(app);
+ assertCpuTime(app2);
+ assertCpuTime(app3);
+ }
// Remove app1 from allowlist.
mProcessStateController.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
@@ -3179,6 +3249,11 @@ public class MockingOomAdjusterTests {
assertFreezeState(app, true);
assertFreezeState(app2, false);
assertFreezeState(app3, false);
+ if (Flags.useCpuTimeCapability()) {
+ assertNoCpuTime(app);
+ assertCpuTime(app2);
+ assertCpuTime(app3);
+ }
// Now remove app2 from allowlist.
mProcessStateController.setUidTempAllowlistStateLSP(MOCKAPP2_UID, false);
@@ -3187,6 +3262,11 @@ public class MockingOomAdjusterTests {
assertFreezeState(app, true);
assertFreezeState(app2, true);
assertFreezeState(app3, true);
+ if (Flags.useCpuTimeCapability()) {
+ assertNoCpuTime(app);
+ assertNoCpuTime(app2);
+ assertNoCpuTime(app3);
+ }
}
@SuppressWarnings("GuardedBy")
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java
index 2988c77703b7..7e052dcba3fd 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_CPU_TIME;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
@@ -64,6 +65,8 @@ import android.content.pm.ServiceInfo;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
@@ -326,6 +329,7 @@ public final class ServiceBindingOomAdjPolicyTest {
@Test
@RequiresFlagsEnabled(com.android.server.am.Flags.FLAG_UNFREEZE_BIND_POLICY_FIX)
+ @DisableFlags(Flags.FLAG_USE_CPU_TIME_CAPABILITY)
public void testServiceDistinctBindingOomAdjShouldNotFreeze() throws Exception {
// Enable the flags.
mSetFlagsRule.enableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
@@ -418,6 +422,7 @@ public final class ServiceBindingOomAdjPolicyTest {
@Test
@RequiresFlagsEnabled(com.android.server.am.Flags.FLAG_UNFREEZE_BIND_POLICY_FIX)
+ @DisableFlags(Flags.FLAG_USE_CPU_TIME_CAPABILITY)
public void testServiceDistinctBindingOomAdjAllowOomManagement() throws Exception {
// Enable the flags.
mSetFlagsRule.enableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
@@ -497,6 +502,7 @@ public final class ServiceBindingOomAdjPolicyTest {
@Test
@RequiresFlagsEnabled(com.android.server.am.Flags.FLAG_UNFREEZE_BIND_POLICY_FIX)
+ @DisableFlags(Flags.FLAG_USE_CPU_TIME_CAPABILITY)
public void testServiceDistinctBindingOomAdjWaivePriority_propagateUnfreeze() throws Exception {
// Enable the flags.
mSetFlagsRule.enableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
@@ -574,6 +580,50 @@ public final class ServiceBindingOomAdjPolicyTest {
}
@Test
+ @RequiresFlagsEnabled({
+ Flags.FLAG_UNFREEZE_BIND_POLICY_FIX,
+ Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY
+ })
+ @EnableFlags(Flags.FLAG_USE_CPU_TIME_CAPABILITY)
+ public void testServiceDistinctBindingOomAdj_propagateCpuTimeCapability() throws Exception {
+ // Note that PROCESS_CAPABILITY_CPU_TIME is special and should be propagated even when
+ // BIND_INCLUDE_CAPABILITIES is not present.
+ performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+ PROCESS_STATE_HOME, HOME_APP_ADJ, PROCESS_CAPABILITY_CPU_TIME, TEST_APP1_NAME,
+ this::setHomeProcess,
+ TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_FOREGROUND_SERVICE,
+ PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+ this::setHasForegroundServices,
+ BIND_AUTO_CREATE,
+ atLeastOnce(), atLeastOnce());
+
+ // BIND_WAIVE_PRIORITY should not affect propagation of capability CPU_TIME
+ performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+ PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_CPU_TIME,
+ TEST_APP1_NAME,
+ this::setHasForegroundServices,
+ TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_HOME, HOME_APP_ADJ,
+ PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+ this::setHomeProcess,
+ BIND_AUTO_CREATE | BIND_WAIVE_PRIORITY,
+ atLeastOnce(), atLeastOnce());
+
+ // If both process have the capability, the bind should not need an update but the unbind
+ // is not safe to skip.
+ // Note that this check can fail on future changes that are not related to
+ // PROCESS_CAPABILITY_CPU_TIME and trigger updates but this is important to ensure
+ // efficiency of OomAdjuster.
+ performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+ PROCESS_STATE_HOME, HOME_APP_ADJ, PROCESS_CAPABILITY_CPU_TIME, TEST_APP1_NAME,
+ this::setHomeProcess,
+ TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_HOME, HOME_APP_ADJ,
+ PROCESS_CAPABILITY_CPU_TIME, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+ this::setHomeProcess,
+ BIND_AUTO_CREATE,
+ never(), atLeastOnce());
+ }
+
+ @Test
@RequiresFlagsDisabled(com.android.server.am.Flags.FLAG_UNFREEZE_BIND_POLICY_FIX)
public void testServiceDistinctBindingOomAdjWaivePriority() throws Exception {
// Enable the flags.
@@ -624,6 +674,9 @@ public final class ServiceBindingOomAdjPolicyTest {
// Enable the flags.
mSetFlagsRule.enableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+ // Note that some capabilities like PROCESS_CAPABILITY_CPU_TIME are special and propagated
+ // regardless of BIND_INCLUDE_CAPABILITIES. We don't test for them here.
+
// Verify that there should be 0 oom adj update
// because we didn't specify the "BIND_INCLUDE_CAPABILITIES"
performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
diff --git a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
index b166514ce0b9..5c73fd33f46f 100644
--- a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
+++ b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
@@ -64,7 +64,6 @@ import android.os.Binder;
import android.os.CpuHeadroomParamsInternal;
import android.os.GpuHeadroomParamsInternal;
import android.os.IBinder;
-import android.os.IHintManager;
import android.os.IHintSession;
import android.os.PerformanceHintManager;
import android.os.Process;
@@ -155,8 +154,6 @@ public class HintManagerServiceTest {
private ActivityManagerInternal mAmInternalMock;
@Mock
private PackageManager mMockPackageManager;
- @Mock
- private IHintManager.IHintManagerClient mClientCallback;
@Rule
public final CheckFlagsRule mCheckFlagsRule =
DeviceFlagsValueProvider.createCheckFlagsRule();
@@ -174,23 +171,6 @@ public class HintManagerServiceTest {
};
}
- private SupportInfo makeDefaultSupportInfo() {
- mSupportInfo = new SupportInfo();
- mSupportInfo.usesSessions = true;
- // By default, mark everything as fully supported
- mSupportInfo.sessionHints = -1;
- mSupportInfo.sessionModes = -1;
- mSupportInfo.modes = -1;
- mSupportInfo.boosts = -1;
- mSupportInfo.sessionTags = -1;
- mSupportInfo.headroom = new SupportInfo.HeadroomSupportInfo();
- mSupportInfo.headroom.isCpuSupported = true;
- mSupportInfo.headroom.cpuMinIntervalMillis = 2000;
- mSupportInfo.headroom.isGpuSupported = true;
- mSupportInfo.headroom.gpuMinIntervalMillis = 2000;
- return mSupportInfo;
- }
-
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -201,7 +181,12 @@ public class HintManagerServiceTest {
mConfig.eventFlagDescriptor = new MQDescriptor<Byte, Byte>();
ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.category = ApplicationInfo.CATEGORY_GAME;
- mSupportInfo = makeDefaultSupportInfo();
+ mSupportInfo = new SupportInfo();
+ mSupportInfo.headroom = new SupportInfo.HeadroomSupportInfo();
+ mSupportInfo.headroom.isCpuSupported = true;
+ mSupportInfo.headroom.cpuMinIntervalMillis = 2000;
+ mSupportInfo.headroom.isGpuSupported = true;
+ mSupportInfo.headroom.gpuMinIntervalMillis = 2000;
when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
when(mMockPackageManager.getNameForUid(anyInt())).thenReturn(TEST_APP_NAME);
when(mMockPackageManager.getApplicationInfo(eq(TEST_APP_NAME), anyInt()))
@@ -230,7 +215,6 @@ public class HintManagerServiceTest {
when(mIPowerMock.getInterfaceVersion()).thenReturn(6);
when(mIPowerMock.getSupportInfo()).thenReturn(mSupportInfo);
when(mIPowerMock.getSessionChannel(anyInt(), anyInt())).thenReturn(mConfig);
- when(mIPowerMock.getSupportInfo()).thenReturn(mSupportInfo);
LocalServices.removeServiceForTest(ActivityManagerInternal.class);
LocalServices.addService(ActivityManagerInternal.class, mAmInternalMock);
}
@@ -425,11 +409,8 @@ public class HintManagerServiceTest {
HintManagerService service = createService();
IBinder token = new Binder();
- IHintManager.HintManagerClientData data = service.getBinderServiceInstance()
- .registerClient(mClientCallback);
-
- final int threadCount = data.maxGraphicsPipelineThreads;
-
+ final int threadCount =
+ service.getBinderServiceInstance().getMaxGraphicsPipelineThreadsCount();
long sessionPtr1 = 1111L;
long sessionId1 = 11111L;
CountDownLatch stopLatch1 = new CountDownLatch(1);
@@ -1274,6 +1255,53 @@ public class HintManagerServiceTest {
}
@Test
+ public void testCpuHeadroomInvalidParams() {
+ HintManagerService service = createService();
+ final CpuHeadroomParamsInternal param1 = new CpuHeadroomParamsInternal();
+ param1.calculationType = 100;
+ assertThrows(IllegalArgumentException.class, () -> {
+ service.getBinderServiceInstance().getCpuHeadroom(param1);
+ });
+
+ final CpuHeadroomParamsInternal param2 = new CpuHeadroomParamsInternal();
+ param2.calculationWindowMillis = 49;
+ assertThrows(IllegalArgumentException.class, () -> {
+ service.getBinderServiceInstance().getCpuHeadroom(param2);
+ });
+ param2.calculationWindowMillis = 10001;
+ assertThrows(IllegalArgumentException.class, () -> {
+ service.getBinderServiceInstance().getCpuHeadroom(param2);
+ });
+
+ final CpuHeadroomParamsInternal param3 = new CpuHeadroomParamsInternal();
+ param3.tids = new int[]{1, 2, 3, 4, 5, 6};
+ assertThrows(IllegalArgumentException.class, () -> {
+ service.getBinderServiceInstance().getCpuHeadroom(param3);
+ });
+ }
+
+ @Test
+ public void testGpuHeadroomInvalidParams() {
+ HintManagerService service = createService();
+ final GpuHeadroomParamsInternal param1 = new GpuHeadroomParamsInternal();
+ param1.calculationType = 100;
+ assertThrows(IllegalArgumentException.class, () -> {
+ service.getBinderServiceInstance().getGpuHeadroom(param1);
+ });
+
+ final GpuHeadroomParamsInternal param2 = new GpuHeadroomParamsInternal();
+ param2.calculationWindowMillis = 49;
+ assertThrows(IllegalArgumentException.class, () -> {
+ service.getBinderServiceInstance().getGpuHeadroom(param2);
+ });
+ param2.calculationWindowMillis = 10001;
+ assertThrows(IllegalArgumentException.class, () -> {
+ service.getBinderServiceInstance().getGpuHeadroom(param2);
+ });
+ }
+
+
+ @Test
public void testCpuHeadroomCache() throws Exception {
CpuHeadroomParamsInternal params1 = new CpuHeadroomParamsInternal();
CpuHeadroomParams halParams1 = new CpuHeadroomParams();
@@ -1419,67 +1447,4 @@ public class HintManagerServiceTest {
verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams1));
verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2));
}
-
- @Test
- public void testRegisteringClient() throws Exception {
- HintManagerService service = createService();
- IHintManager.HintManagerClientData data = service.getBinderServiceInstance()
- .registerClient(mClientCallback);
- assertNotNull(data);
- assertEquals(data.supportInfo, mSupportInfo);
- }
-
- @Test
- public void testRegisteringClientOnV4() throws Exception {
- when(mIPowerMock.getInterfaceVersion()).thenReturn(4);
- HintManagerService service = createService();
- IHintManager.HintManagerClientData data = service.getBinderServiceInstance()
- .registerClient(mClientCallback);
- assertNotNull(data);
- assertEquals(data.supportInfo.usesSessions, true);
- assertEquals(data.supportInfo.boosts, 0);
- assertEquals(data.supportInfo.modes, 0);
- assertEquals(data.supportInfo.sessionHints, 31);
- assertEquals(data.supportInfo.sessionModes, 0);
- assertEquals(data.supportInfo.sessionTags, 0);
- assertEquals(data.powerHalVersion, 4);
- assertEquals(data.preferredRateNanos, DEFAULT_HINT_PREFERRED_RATE);
- }
-
- @Test
- public void testRegisteringClientOnV5() throws Exception {
- when(mIPowerMock.getInterfaceVersion()).thenReturn(5);
- HintManagerService service = createService();
- IHintManager.HintManagerClientData data = service.getBinderServiceInstance()
- .registerClient(mClientCallback);
- assertNotNull(data);
- assertEquals(data.supportInfo.usesSessions, true);
- assertEquals(data.supportInfo.boosts, 0);
- assertEquals(data.supportInfo.modes, 0);
- assertEquals(data.supportInfo.sessionHints, 255);
- assertEquals(data.supportInfo.sessionModes, 1);
- assertEquals(data.supportInfo.sessionTags, 31);
- assertEquals(data.powerHalVersion, 5);
- assertEquals(data.preferredRateNanos, DEFAULT_HINT_PREFERRED_RATE);
- }
-
- @Test
- public void testSettingUpOldClientWhenUnsupported() throws Exception {
- when(mIPowerMock.getInterfaceVersion()).thenReturn(5);
- // Mock unsupported to modify the default support behavior
- when(mNativeWrapperMock.halGetHintSessionPreferredRate())
- .thenReturn(-1L);
- HintManagerService service = createService();
- IHintManager.HintManagerClientData data = service.getBinderServiceInstance()
- .registerClient(mClientCallback);
- assertNotNull(data);
- assertEquals(data.supportInfo.usesSessions, false);
- assertEquals(data.supportInfo.boosts, 0);
- assertEquals(data.supportInfo.modes, 0);
- assertEquals(data.supportInfo.sessionHints, 0);
- assertEquals(data.supportInfo.sessionModes, 0);
- assertEquals(data.supportInfo.sessionTags, 0);
- assertEquals(data.powerHalVersion, 5);
- assertEquals(data.preferredRateNanos, -1);
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/app/GameManagerServiceSettingsTests.java b/services/tests/servicestests/src/com/android/server/app/GameManagerServiceSettingsTests.java
index fde3422b1ff3..17f5ebb3b02a 100644
--- a/services/tests/servicestests/src/com/android/server/app/GameManagerServiceSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/app/GameManagerServiceSettingsTests.java
@@ -130,9 +130,9 @@ public class GameManagerServiceSettingsTests {
assertEquals(GameManager.GAME_MODE_STANDARD, settings.getGameModeLocked(PACKAGE_NAME_4));
// test game mode configs
- assertNull(settings.getConfigOverride(PACKAGE_NAME_1));
- assertNull(settings.getConfigOverride(PACKAGE_NAME_3));
- GamePackageConfiguration config = settings.getConfigOverride(PACKAGE_NAME_2);
+ assertNull(settings.getConfigOverrideLocked(PACKAGE_NAME_1));
+ assertNull(settings.getConfigOverrideLocked(PACKAGE_NAME_3));
+ GamePackageConfiguration config = settings.getConfigOverrideLocked(PACKAGE_NAME_2);
assertNotNull(config);
assertNull(config.getGameModeConfiguration(GameManager.GAME_MODE_STANDARD));
@@ -152,7 +152,7 @@ public class GameManagerServiceSettingsTests {
assertEquals(batteryConfig.getFpsStr(), GameModeConfiguration.DEFAULT_FPS);
assertFalse(batteryConfig.getUseAngle());
- config = settings.getConfigOverride(PACKAGE_NAME_4);
+ config = settings.getConfigOverrideLocked(PACKAGE_NAME_4);
assertNotNull(config);
GameModeConfiguration customConfig = config.getGameModeConfiguration(
GameManager.GAME_MODE_CUSTOM);
@@ -177,7 +177,7 @@ public class GameManagerServiceSettingsTests {
GameManagerSettings settings = new GameManagerSettings(context.getFilesDir());
assertTrue(settings.readPersistentDataLocked());
- final GamePackageConfiguration config = settings.getConfigOverride(PACKAGE_NAME_1);
+ final GamePackageConfiguration config = settings.getConfigOverrideLocked(PACKAGE_NAME_1);
assertNotNull(config);
final GameModeConfiguration batteryConfig = config.getGameModeConfiguration(
GameManager.GAME_MODE_BATTERY);
@@ -218,7 +218,7 @@ public class GameManagerServiceSettingsTests {
assertEquals(2, settings.getGameModeLocked(PACKAGE_NAME_2));
assertEquals(3, settings.getGameModeLocked(PACKAGE_NAME_3));
- final GamePackageConfiguration config = settings.getConfigOverride(PACKAGE_NAME_2);
+ final GamePackageConfiguration config = settings.getConfigOverrideLocked(PACKAGE_NAME_2);
assertNotNull(config);
final GameModeConfiguration batteryConfig = config.getGameModeConfiguration(
GameManager.GAME_MODE_BATTERY);
@@ -248,7 +248,7 @@ public class GameManagerServiceSettingsTests {
GameModeConfiguration batteryConfig = config.getOrAddDefaultGameModeConfiguration(
GameManager.GAME_MODE_BATTERY);
batteryConfig.setScaling(0.77f);
- settings.setConfigOverride(PACKAGE_NAME_2, config);
+ settings.setConfigOverrideLocked(PACKAGE_NAME_2, config);
// set config for app4
config = new GamePackageConfiguration(PACKAGE_NAME_4);
@@ -256,15 +256,15 @@ public class GameManagerServiceSettingsTests {
GameManager.GAME_MODE_CUSTOM);
customConfig.setScaling(0.4f);
customConfig.setFpsStr("30");
- settings.setConfigOverride(PACKAGE_NAME_4, config);
+ settings.setConfigOverrideLocked(PACKAGE_NAME_4, config);
settings.writePersistentDataLocked();
// clear the settings in memory
- settings.removeGame(PACKAGE_NAME_1);
- settings.removeGame(PACKAGE_NAME_2);
- settings.removeGame(PACKAGE_NAME_3);
- settings.removeGame(PACKAGE_NAME_4);
+ settings.removeGameLocked(PACKAGE_NAME_1);
+ settings.removeGameLocked(PACKAGE_NAME_2);
+ settings.removeGameLocked(PACKAGE_NAME_3);
+ settings.removeGameLocked(PACKAGE_NAME_4);
// read back in and verify
assertTrue(settings.readPersistentDataLocked());
@@ -273,9 +273,9 @@ public class GameManagerServiceSettingsTests {
assertEquals(1, settings.getGameModeLocked(PACKAGE_NAME_3));
assertEquals(1, settings.getGameModeLocked(PACKAGE_NAME_4));
- config = settings.getConfigOverride(PACKAGE_NAME_1);
+ config = settings.getConfigOverrideLocked(PACKAGE_NAME_1);
assertNull(config);
- config = settings.getConfigOverride(PACKAGE_NAME_2);
+ config = settings.getConfigOverrideLocked(PACKAGE_NAME_2);
assertNotNull(config);
batteryConfig = config.getGameModeConfiguration(GameManager.GAME_MODE_BATTERY);
assertNotNull(batteryConfig);
@@ -292,7 +292,7 @@ public class GameManagerServiceSettingsTests {
assertEquals(performanceConfig.getFpsStr(), "60");
assertTrue(performanceConfig.getUseAngle());
- config = settings.getConfigOverride(PACKAGE_NAME_4);
+ config = settings.getConfigOverrideLocked(PACKAGE_NAME_4);
assertNotNull(config);
customConfig = config.getGameModeConfiguration(GameManager.GAME_MODE_CUSTOM);
assertNotNull(customConfig);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenDeviceEffectsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenDeviceEffectsTest.java
index 3ac78908d8ae..af911e811e5e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenDeviceEffectsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenDeviceEffectsTest.java
@@ -49,18 +49,22 @@ public class ZenDeviceEffectsTest extends UiServiceTestCase {
@Test
public void builder() {
- ZenDeviceEffects deviceEffects = new ZenDeviceEffects.Builder()
- .setShouldDimWallpaper(true)
- .setShouldDisableTapToWake(true).setShouldDisableTapToWake(false)
- .setShouldDisableTiltToWake(true)
- .setShouldMaximizeDoze(true)
- .setShouldUseNightMode(false)
- .setShouldSuppressAmbientDisplay(false).setShouldSuppressAmbientDisplay(true)
- .addExtraEffect("WILL BE GONE")
- .setExtraEffects(ImmutableSet.of("1", "2"))
- .addExtraEffects(ImmutableSet.of("3", "4"))
- .addExtraEffect("5")
- .build();
+ ZenDeviceEffects deviceEffects =
+ new ZenDeviceEffects.Builder()
+ .setShouldDimWallpaper(true)
+ .setShouldDisableTapToWake(true)
+ .setShouldDisableTapToWake(false)
+ .setShouldDisableTiltToWake(true)
+ .setShouldMaximizeDoze(true)
+ .setShouldUseNightMode(false)
+ .setShouldUseNightLight(true)
+ .setShouldSuppressAmbientDisplay(false)
+ .setShouldSuppressAmbientDisplay(true)
+ .addExtraEffect("WILL BE GONE")
+ .setExtraEffects(ImmutableSet.of("1", "2"))
+ .addExtraEffects(ImmutableSet.of("3", "4"))
+ .addExtraEffect("5")
+ .build();
assertThat(deviceEffects.shouldDimWallpaper()).isTrue();
assertThat(deviceEffects.shouldDisableAutoBrightness()).isFalse();
@@ -68,6 +72,7 @@ public class ZenDeviceEffectsTest extends UiServiceTestCase {
assertThat(deviceEffects.shouldDisableTiltToWake()).isTrue();
assertThat(deviceEffects.shouldDisableTouch()).isFalse();
assertThat(deviceEffects.shouldDisplayGrayscale()).isFalse();
+ assertThat(deviceEffects.shouldUseNightLight()).isTrue();
assertThat(deviceEffects.shouldMaximizeDoze()).isTrue();
assertThat(deviceEffects.shouldMinimizeRadioUsage()).isFalse();
assertThat(deviceEffects.shouldUseNightMode()).isFalse();
@@ -85,15 +90,18 @@ public class ZenDeviceEffectsTest extends UiServiceTestCase {
.addExtraEffect("1")
.build();
- ZenDeviceEffects modified = new ZenDeviceEffects.Builder(original)
- .setShouldDisplayGrayscale(true)
- .setShouldUseNightMode(false)
- .addExtraEffect("2")
- .build();
+ ZenDeviceEffects modified =
+ new ZenDeviceEffects.Builder(original)
+ .setShouldDisplayGrayscale(true)
+ .setShouldUseNightMode(false)
+ .setShouldUseNightLight(true)
+ .addExtraEffect("2")
+ .build();
assertThat(modified.shouldDimWallpaper()).isTrue(); // from original
assertThat(modified.shouldDisableTiltToWake()).isTrue(); // from original
assertThat(modified.shouldDisplayGrayscale()).isTrue(); // updated
+ assertThat(modified.shouldUseNightLight()).isTrue(); // updated
assertThat(modified.shouldUseNightMode()).isFalse(); // updated
assertThat(modified.shouldSuppressAmbientDisplay()).isTrue(); // from original
assertThat(modified.getExtraEffects()).containsExactly("1", "2"); // updated
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index 3236f9501324..b42a6a5a7382 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -18,7 +18,6 @@ package com.android.server.notification;
import static android.app.AutomaticZenRule.TYPE_BEDTIME;
import static android.app.Flags.FLAG_BACKUP_RESTORE_LOGGING;
-import static android.app.Flags.FLAG_MODES_API;
import static android.app.Flags.FLAG_MODES_UI;
import static android.app.Flags.modesUi;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
@@ -26,7 +25,6 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCRE
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static android.app.NotificationManager.Policy.suppressedEffectsToString;
-import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG;
import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_RULES;
import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
import static android.provider.Settings.Global.ZEN_MODE_OFF;
@@ -56,9 +54,7 @@ import static junit.framework.TestCase.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -71,7 +67,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Parcel;
-import android.os.UserHandle;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.FlagsParameterization;
@@ -100,6 +95,9 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.xmlpull.v1.XmlPullParserException;
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
@@ -108,9 +106,6 @@ import java.io.IOException;
import java.time.Instant;
import java.util.List;
-import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
-import platform.test.runner.parameterized.Parameters;
-
@SmallTest
@RunWith(ParameterizedAndroidJunit4.class)
public class ZenModeConfigTest extends UiServiceTestCase {
@@ -731,19 +726,21 @@ public class ZenModeConfigTest extends UiServiceTestCase {
rule.setConditionOverride(OVERRIDE_DEACTIVATE);
rule.pkg = OWNER.getPackageName();
rule.zenPolicy = POLICY;
- rule.zenDeviceEffects = new ZenDeviceEffects.Builder()
- .setShouldDisplayGrayscale(false)
- .setShouldSuppressAmbientDisplay(true)
- .setShouldDimWallpaper(false)
- .setShouldUseNightMode(true)
- .setShouldDisableAutoBrightness(false)
- .setShouldDisableTapToWake(true)
- .setShouldDisableTiltToWake(false)
- .setShouldDisableTouch(true)
- .setShouldMinimizeRadioUsage(false)
- .setShouldMaximizeDoze(true)
- .setExtraEffects(ImmutableSet.of("one", "two"))
- .build();
+ rule.zenDeviceEffects =
+ new ZenDeviceEffects.Builder()
+ .setShouldDisplayGrayscale(false)
+ .setShouldSuppressAmbientDisplay(true)
+ .setShouldDimWallpaper(false)
+ .setShouldUseNightMode(true)
+ .setShouldDisableAutoBrightness(false)
+ .setShouldDisableTapToWake(true)
+ .setShouldDisableTiltToWake(false)
+ .setShouldDisableTouch(true)
+ .setShouldMinimizeRadioUsage(false)
+ .setShouldMaximizeDoze(true)
+ .setShouldUseNightLight(true)
+ .setExtraEffects(ImmutableSet.of("one", "two"))
+ .build();
rule.creationTime = CREATION_TIME;
rule.allowManualInvocation = ALLOW_MANUAL;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java
index c6cc941ba1cd..b138c72875a6 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java
@@ -54,6 +54,9 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@@ -67,10 +70,6 @@ import java.util.List;
import java.util.Optional;
import java.util.Set;
-import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
-import platform.test.runner.parameterized.Parameters;
-
-
@SmallTest
@RunWith(ParameterizedAndroidJunit4.class)
@TestableLooper.RunWithLooper
@@ -232,6 +231,7 @@ public class ZenModeDiffTest extends UiServiceTestCase {
+ "mDisableTouch:true->false, "
+ "mMinimizeRadioUsage:true->false, "
+ "mMaximizeDoze:true->false, "
+ + "mNightLight:true->false, "
+ "mExtraEffects:[effect1]->[effect2]}, "
+ "triggerDescription:string1->string2, "
+ "type:2->1, "
@@ -358,18 +358,21 @@ public class ZenModeDiffTest extends UiServiceTestCase {
generateFieldDiffs(effects1, effects2, fieldsForDiff, expectedFrom, expectedTo);
d = new ZenModeDiff.DeviceEffectsDiff(effects1, effects2);
- assertThat(d.toString()).isEqualTo("ZenDeviceEffectsDiff{"
- + "mGrayscale:true->false, "
- + "mSuppressAmbientDisplay:true->false, "
- + "mDimWallpaper:true->false, "
- + "mNightMode:true->false, "
- + "mDisableAutoBrightness:true->false, "
- + "mDisableTapToWake:true->false, "
- + "mDisableTiltToWake:true->false, "
- + "mDisableTouch:true->false, "
- + "mMinimizeRadioUsage:true->false, "
- + "mMaximizeDoze:true->false, "
- + "mExtraEffects:[effect1]->[effect2]}");
+ assertThat(d.toString())
+ .isEqualTo(
+ "ZenDeviceEffectsDiff{"
+ + "mGrayscale:true->false, "
+ + "mSuppressAmbientDisplay:true->false, "
+ + "mDimWallpaper:true->false, "
+ + "mNightMode:true->false, "
+ + "mDisableAutoBrightness:true->false, "
+ + "mDisableTapToWake:true->false, "
+ + "mDisableTiltToWake:true->false, "
+ + "mDisableTouch:true->false, "
+ + "mMinimizeRadioUsage:true->false, "
+ + "mMaximizeDoze:true->false, "
+ + "mNightLight:true->false, "
+ + "mExtraEffects:[effect1]->[effect2]}");
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 09da0156eb82..1884bbd39bb9 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -202,6 +202,9 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.xmlpull.v1.XmlPullParserException;
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
@@ -221,9 +224,6 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
-import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
-import platform.test.runner.parameterized.Parameters;
-
@SmallTest
@SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service.
@RunWith(ParameterizedAndroidJunit4.class)
@@ -2759,18 +2759,20 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
@EnableFlags(FLAG_MODES_API)
public void addAutomaticZenRule_fromApp_ignoresHiddenEffects() {
- ZenDeviceEffects zde = new ZenDeviceEffects.Builder()
- .setShouldDisplayGrayscale(true)
- .setShouldSuppressAmbientDisplay(true)
- .setShouldDimWallpaper(true)
- .setShouldUseNightMode(true)
- .setShouldDisableAutoBrightness(true)
- .setShouldDisableTapToWake(true)
- .setShouldDisableTiltToWake(true)
- .setShouldDisableTouch(true)
- .setShouldMinimizeRadioUsage(true)
- .setShouldMaximizeDoze(true)
- .build();
+ ZenDeviceEffects zde =
+ new ZenDeviceEffects.Builder()
+ .setShouldDisplayGrayscale(true)
+ .setShouldSuppressAmbientDisplay(true)
+ .setShouldDimWallpaper(true)
+ .setShouldUseNightMode(true)
+ .setShouldDisableAutoBrightness(true)
+ .setShouldDisableTapToWake(true)
+ .setShouldDisableTiltToWake(true)
+ .setShouldDisableTouch(true)
+ .setShouldMinimizeRadioUsage(true)
+ .setShouldMaximizeDoze(true)
+ .setShouldUseNightLight(true)
+ .build();
String ruleId = mZenModeHelper.addAutomaticZenRule(UserHandle.CURRENT,
mContext.getPackageName(),